How to start a Typescript app with SystemJS modules?
Asked Answered
C

1

5

I am using the typescript compiler to bundle my modules into one main.js file, using these settings in tsconfig.json:

"module": "system",
"out": "docs/js/main.js"

This works, so according to the SystemJS documentation, I only have to include the SystemJS production file and kickstart the app with these tags in my HTML:

<script src="js/system.js"></script>
<script>
  SystemJS.import('js/main.js');
</script> 

My app:

import { Message } from "./message";

export class App {
    constructor() {
        let demomessage = new Message("hello");
    }
}

export class Message {      
    constructor(str:string) {
        console.log(str);
    }
}

This results in this javascript code in main.js:

System.register("message", ...) {
    // message code here
});
System.register("app", ...) {
    // app code here
});

The part that I'm missing (and that's also not explained in Microsoft's always-lacking-Typescript-documentation) is how to actually start the app... How does SystemJS know which class is the starting point? Even if I just put console.log in my app it doesn't execute....

EDIT

I discovered that using system.js instead of system-production.js at least starts the process. After a lot of fiddling I got my app to start with the following code, but it looks weird and ugly. Is this how it's supposed to work???

<script src="js/system.js"></script>
<script>
  // get the anonymous scope
  System.import('js/main.js')
    .then(function() {
      // now we can get to the app and make a new instance
      System.import('app').then(function(m){
         let app = new m.App();
      })
    });
</script>
Commemorative answered 2/6, 2017 at 12:10 Comment(4)
Yes that's how it's supposed to work. The first import loads the bundle just to pre-populate the module registry, there's nothing within the bundle telling which module should be executed, that's the purpose of the second import.Dihedral
Thanks, but is there any way in which the app can start itself after being loaded? Most systemjs tutorials only mention import(js/main.js) and that seems to be enough...?Commemorative
There's no way if js/main.js is a bundle containing several modules, in other words, it has several System.register() calls. I'd guess all the tutorials assume it's a single module, maybe built with rollup, or just unbundled and loading all other modules separately.Dihedral
Thanks. The Typescript / SystemJS documentation says that you can bundle all modules in one .js file, and then use system-production.js to load everything. But apart from the fact that that doesn't work, it also doesn't mention how to instantiate the app.... it's kind of frustrating :)Commemorative
C
6

After much head-scratching I found out the answer is more simple than expected: just load the bundle first as a regular .js file, and then you can import the app directly:

<script src="js/system.js"></script>
<script src="js/main.js"></script>
<script>
  System.import('app').then(function(module) {
    let a = new module.App();
  });
</script>
Commemorative answered 11/6, 2017 at 16:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.