5

We are considering moving some of our angular projects over to typescript and having some trouble with internal module/namespaces.

We posted this working example on github: https://github.com/hikirsch/TypeScriptSystemJSAngularSampleApp

steps:

npm install jspm -g
npm install
cd src/
jspm install
jspm install --dev
cd ..
gulp bundle
cd src/
python -m SimpleHTTPServer

This is the gist of the application: index.ts

/// <reference path="../typings/tsd.d.ts" />
/// <reference path="../typings/typescriptApp.d.ts" />

import * as angular from 'angular';

import {ExampleCtrl} from './controllers/ExampleCtrl';
import {ExampleTwoCtrl} from './controllers/ExampleTwoCtrl';

export var app = angular.module("myApp", []);

app.controller("ExampleCtrl", ExampleCtrl);
app.controller("ExampleTwoCtrl", ExampleTwoCtrl);

ExampleCtrl.ts

/// <reference path="../../typings/tsd.d.ts" />
/// <reference path="../../typings/typescriptApp.d.ts" />


export class ExampleCtrl {
    public static $inject:Array<string> = [];

    constructor() {

    }

    public name:string;
    public hello_world:string;

    public say_hello() {
        console.log('greeting');

        this.hello_world = "Hello, " + this.name + "!";
    }
}

ExampleTwoCtrl.ts

/// <reference path="../../typings/tsd.d.ts" />
/// <reference path="../../typings/typescriptApp.d.ts" />

export class ExampleTwoCtrl {
    public static $inject:Array<string> = [];

    constructor() {

    }

    public name:string;
    public text:string;

    public second() {
        this.text = "ExampleTwoCtrl: " +  this.name;
    }
}

As stated, this works all well and good. But we'd rather have everything under a namespace like this:

module myApp.controllers {
    export class ExampleController {
        ...
    }
}
//do we need to export something here?

and then use it like this:

This will compile correctly running the gulp bundle task but give an error in the browser /// ///

import * as angular from 'angular';

import ExampleCtrl = myApp.controllers.ExampleCtrl;
import ExampleTwoCtrl = myApp.controllers.ExampleTwoCtrl;

export var app = angular.module("myApp", []);

app.controller("ExampleCtrl", ExampleCtrl);
app.controller("ExampleTwoCtrl", ExampleTwoCtrl);

browser error:

Uncaught ReferenceError: myApp is not defined(anonymous function) @ build.js:5u @ build.js:1i @ build.js:1c @ build.js:1(anonymous function) @ build.js:1(anonymous function) @ build.js:1
build.js:1 Uncaught Error: [$injector:modulerr] Failed to instantiate module myApp due to:
Error: [$injector:nomod] Module 'myApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.3.15/$injector/nomod?p0=myApp
    at http://localhost:8000/build/build.js:1:4007
    at http://localhost:8000/build/build.js:1:12353
    at e (http://localhost:8000/build/build.js:1:11925)
    at t.register.e (http://localhost:8000/build/build.js:1:12237)
    at http://localhost:8000/build/build.js:1:20741
    at o (http://localhost:8000/build/build.js:1:4392)
    at p (http://localhost:8000/build/build.js:1:20519)
    at Bt (http://localhost:8000/build/build.js:1:22209)
    at t.register.s (http://localhost:8000/build/build.js:1:10038)
    at Q (http://localhost:8000/build/build.js:1:10348)
http://errors.angularjs.org/1.3.15/$injector/modulerr?p0=myApp&p1=Error%3A%…0%20at%20Q%20(http%3A%2F%2Flocalhost%3A8000%2Fbuild%2Fbuild.js%3A1%3A10348)
stuffins
  • 53
  • 1
  • 5

1 Answers1

2

According to typescript documentation you do not need to use internal modules when compiling to commonjs. As stated:

A key feature of external modules in TypeScript is that two different external modules will never contribute names to the same scope. Because the consumer of an external module decides what name to assign it, there's no need to proactively wrap up the exported symbols in a namespace.

I have found the best way to use typescript with a commonjs loader (I am using browserify) is to do something like:

class ExampleTwoCtrl {
    public static $inject:Array<string> = [];

    constructor() {

    }

    public name:string;
    public text:string;

    public second() {
        this.text = "ExampleTwoCtrl: " +  this.name;
    }
}

export = ExampleTwoCtrl

and the use it like:

import MyController = require('./ExampleTwoCtrl');
var a = new MyController();

That being said, I watched the recording from John Papa's talk at AngularU where they demonstrated some code bundled using systemjs written in typescript without any imports, just internal ts modules. I asked on twitter where I could find the sample code, but haven't got a response yet.

masimplo
  • 3,674
  • 2
  • 30
  • 47
  • The sample code there were using is linked to here on slide 18 https://docs.google.com/presentation/d/1ETDm0R_BxZUcumqDxnG8puKbq_gHvMZyOwmq09wUk68/edit#slide=id.ga1ef308f1_0_56 – stuffins Jun 26 '15 at 21:02
  • The approach they use essentially just dumps a script tag for every JS in the project onto the html page regardless if its being used or not. We were looking for an approach where we could tell it which file starts the app and have it build the file appropriately. What we have without using modules seems to accomplish it. Just trying to figure out how we can make that work with modules (essentially just want everything namespaced) – stuffins Jun 26 '15 at 21:14
  • I thought so too, but it's not. If you check index.html (https://github.com/johnpapa/hottowel-angular-typescript/blob/master/src/client/index.html) it does not use systemjs at all. The code they where showing was different, as there was a systemjs and some other files and a single script that loads main.js (if I remember correctly, min 50 of the video) – masimplo Jun 26 '15 at 21:20
  • also @1:05 there is an example of `System.import('app/app')` in `index.html` and then the `app.ts` containing the configuraion, import and bootstrap of all the other stuff. – ciekawy Dec 02 '15 at 13:23
  • I actually spoke with John papa on this matter, I don't think he would go the route with SystemJS. I think he prefer to bundle everything at once and load it. I think he believe in general situation, your javascript files excludes vendor files shouldn't be that big. – maxisam Jan 05 '16 at 15:35