Click here to Skip to main content
15,879,535 members
Articles / Programming Languages / Typescript

module based architect in typescript

Rate me:
Please Sign up or sign in to vote.
5.00/5 (5 votes)
20 Jul 2016CPOL6 min read 8.2K   2  
Module based architect in TypeScript

Introduction

This article contains how typescript developer can combine their modules and use combined javascript output 

functionality in other expected items. Suppose your application has a couple of features, and you want to bundle each part of the application and use it.

this article is going to implement this features operationally.

Background

A variety of developers using AMD (Asynchronous Module Definition) module based on their projects, for that we should use third party tools such as requirejs, and in typescript code use "import/from" reserve word to import other modules.

For instance, module "B" needs module "A" functionality, we import module "A" into module "B" and require that to load module "A" asynchronously.

Each module can have multiple imported to another too and require js should find all imports, using regex and load other files asynchronously. we know requirejs for having better performance use singleton pattern and the loaded modules don't need to have a process on that loaded files repetitive.

In this article we want use typescript built-in compiler to combine and bundle modules and create modern architecture.

Solution

I use my favorite IDE "Visual Studio", you can almost use any IDE/TextEditor you want (but you may have some little changes in this article to build up successfully).

First, I'm going to create empty asp.net project using visual studio without any additional references.

I named this project "architect" and this is my solution.

It's absolutely obvious and clear.

If you don't have typescript, you should easily install that using typescriptlang, I use visual studio 2015 update 2 so, I had installed this on my machine.

Cool, I create a folder named "Application" on a root of the project and I created two subFolder named for instance "Foundation" & "Services".

So, we have "Application" folder and into this, we have "Foundation" and "Services".

and now, we want to create some typescript files to handle our architecture features.

Inside folder "Foundation" I create two typescript files named "foundation1.ts" and "foundation2.ts". I open foundation1.ts item and code like this 

JavaScript
// Application/Foundation/foundation1.ts 

module Foundation {
    export class foundation1 {
        static method1(str: string) {
            console.log(`method1 in foundation1: ${str}`);
        }
    }
}

Foundation.foundation1.method1('Author => Ali Khalili');

I think its code is obvious for any typescript developer and does not need to explain more.

and now I want to code in foundation2.ts like this

JavaScript
// Application/Foundation/foundation2.ts

module Foundation {
    export class foundation2 {
        static method2(str: string) {
            console.log(`method1 in foundation2: ${str}`);
        }
    }
}

and you see this item completely like foundation1.ts, just has a different naming.

Now, we need "tsconfig.json" to manage typescript compiler in this root and force these two items to combined in just one file.

In visual studio you can 'Add - new Item' and find "Typescript json configuration" and create that in Foundation folder, now you have "tsconfig.json".

If you don't find Typescript json configuration,  no problem, you can manually create tsconfig.json and fill that like this

JavaScript
// Application/Foundation/tsconfig.json

{
  "compilerOptions": {
    //"watch": true,
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": false,
    "target": "es6",
    "outFile": "outPutFoundation.js"
  },
  "compileOnSave": true,
  "exclude": [
    "node_modules",
    "wwwroot"
  ]
}

It means compiler must generate es6 code, and outFile is going to create and named "outPutFoundation.js".

Cool, save and build your solution and now you should have something like this

If you don't see outPutFoundation.js, it's enough in "solution explorer" click on "Show All Files"

If you have some additional files like "foundation1.js" and "foundation2.js", It's cause of initial typescript compiler started by visual studio, delete those and after create tsconfig.json these items will not appear again.

Ok, I want you to view outPutFoundation.js and scrutiny of this item.

JavaScript
// Application/Foundation/outPutFoundation.js

var Foundation;
(function (Foundation) {
    class foundation1 {
        static method1(str) {
            Foundation.foundation2.method2(str);
            console.log(`method1 in foundation1: ${str}`);
        }
    }
    Foundation.foundation1 = foundation1;
})(Foundation || (Foundation = {}));
Foundation.foundation1.method1('Author => Ali Khalili');
var Foundation;
(function (Foundation) {
    class foundation2 {
        static method2(str) {
            console.log(`method1 in foundation2: ${str}`);
        }
    }
    Foundation.foundation2 = foundation2;
})(Foundation || (Foundation = {}));

Isn't cool ? by the tsconfig that we had created in Foundation folder it promises us to compile all typescript files and combine those to just one item, later we can minimize that with third party tools like gulp.js. this is not contained in this article by you can find out more in gulpjs

Ok, now we need index.html in a root of the project, create that and reference otPutFoundation.js to this, run the project and open your browser console, you well see this string

"method1 in foundation1: Author => Ali Khalili"

As you see, typescript compiler first, created foundation1 and next foundation2, assume that method1 in foundation1 calls method2 in foundation2 class,

we need some change in foundation1 code like this

JavaScript
module Foundation {
    export class foundation1 {
        static method1(str: string) {
            foundation2.method2(str);
            console.log(`method1 in foundation1: ${str}`);
        }
    }
}

Foundation.foundation1.method1('Author => Ali Khalili');

What will happen? as you probably guess , after running the project we have error cause of this added line code!

foundation2.method2(str);

This line makes error cause foundation2 has not created yet and invoked after foundation1, now what can we do to solve this problem?

There is an easy solution, just enough to add a reference path to a top of the foundation1.ts,  it explicitly tells typescript compiler, this item needs foundation2.ts

So, we should change foundation1.ts like this

JavaScript
/// <reference path="foundation2.ts" />

module Foundation {
    export class foundation1 {
        static method1(str: string) {
            foundation2.method2(str);
            console.log(`method1 in foundation1: ${str}`);
        }
    }
}

Foundation.foundation1.method1('Author => Ali Khalili');

Just save project, happened something incredible, typescript compiler automatically changes destination file and now outPutFoundation.js changed to something like this

JavaScript
var Foundation;
(function (Foundation) {
    class foundation2 {
        static method2(str) {
            console.log(`method1 in foundation2: ${str}`);
        }
    }
    Foundation.foundation2 = foundation2;
})(Foundation || (Foundation = {}));
/// <reference path="foundation2.ts" />
var Foundation;
(function (Foundation) {
    class foundation1 {
        static method1(str) {
            Foundation.foundation2.method2(str);
            console.log(`method1 in foundation1: ${str}`);
        }
    }
    Foundation.foundation1 = foundation1;
})(Foundation || (Foundation = {}));
Foundation.foundation1.method1('Author => Ali Khalili');

As you see our code changed, first invoke foundation2, after that foundation1 will invoked! So, now every thing is cool and there is no problem and you see string output in your browser console.

Multiple Project Architecture

but if you have multiple projects or you want lazy load some items and its not logical to bundle all your typescript files into a one file!

Now it's time to implement Services with some typescript file, int this part I wanna show you something amazing in typescript compiler.

Inside Services folder create "service1.ts", note that in this time because the lack of tsconfig.json after save or build, compiler doesn't generate its js file!

now inside this folder we create tsconfig.json and just we changed outFile to "outPutService.js"

our solution is like this now

Cool, assume that we want use service1 and it functions in foundation1; of course we can't use import cause our module architect is completely made in a different way.

In index.html we should have some code like this  

JavaScript
// index.html

<h1>Hello World</h1>

<script src="Application/Services/outPutService.js"></script>

<script src="Application/Foundation/outPutFoundation.js"></script>

Ok, we call service before foundation so how call service1.method1('some string') ?

Typescript has a feature named "Ambient Modules" let us declare all needed files.

So, again imagine what we want to do; we want use service1 functionality in foundation1, for this reason, we called outPutService.js before outPutFoundation.js , its ok but how to call needed function in foundation1

Answer this question as I said is ambient modules

Inside Foundation folder , create Definition folder and inside that create typescript file that named "service1.d.ts" and its code is like this

JavaScript
// Foundation/Definition/service1.d.ts

declare module Service {
    class service1 {
        static method1(str: string): void;
    }
}

As you see, we declare "Service" module, and it's class , etc

Now we can call this function and be using cool strong type support.

We should change foundation1.ts code to something like this

JavaScript
/// <reference path="foundation2.ts" />

module Foundation {
    export class foundation1 {
        static method1(str: string) {
            Service.service1.method1(str);
            foundation2.method2(str);
            console.log(`method1 in foundation1: ${str}`);
        }
    }
}

Foundation.foundation1.method1('Author => Ali Khalili');

Everything is done; now run the project and see console in your browser

You should see something amazing like this

Conclusion

Of course this article just has educational aspects, for example in this scenario you could bundle all your files, but if you have a large and scalable application this solution can helps you in a varity of problems and make your application more clear and usable.

Code

You can clone all of this article codes using my github account

Github

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Iran (Islamic Republic of) Iran (Islamic Republic of)
I'm Ali Khalili
senior consultant - software developer/architect
love anything modern such as .Net core - typescript (& es6 - angularjs - reactjs)
and other cool Microsoft technologies

Comments and Discussions

 
-- There are no messages in this forum --