Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Executing a module from a bundled file using SystemJS and TypeScript

I have a simple TypeScript project with 2 classes: Main.ts and Ball.ts, first is importing the second one. I'm trying to create a setup similar to AS3 project, where you have one entry point class that triggers all other things to happen. I want to compile all js into a single file so I could load it more efficiently. Files I have:

Main.ts

import Ball from "./Ball";

class Main {
    a: number = 10;

    constructor() {
        console.log("Hello from Main!");
        let ball:Ball = new Ball();
    }
}

let main = new Main();

Ball.ts

export default class Ball{
    shape:string = "round";
    constructor(){
        console.log("Ball has been created");
    }
}

TS Configuration I'm using:

{
  "compilerOptions": {
        "target": "es5",
        "module": "amd", 
        "outFile": "./public/js/bundle.js",
        "strict": true
    }
}

To use amd modules in js I use SystemJS:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>Hello</h1>
<script type="text/javascript" src="js/system.js"></script>
<script>
    SystemJS.config({
        baseURL: '/js'
    });
    SystemJS.import('bundle.js');
</script>
</body>
</html>

Compiled js file looks like this:

define("Ball", ["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var Ball = (function () {
        function Ball() {
            this.shape = "round";
            console.log("Ball has been created");
        }
        return Ball;
    }());
    exports.default = Ball;
});
define("Main", ["require", "exports", "Ball"], function (require, exports, Ball_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var Main = (function () {
        function Main() {
            this.a = 10;
            console.log("Hello from Main!");
            var ball = new Ball_1.default();
        }
        return Main;
    }());
    var main = new Main();
});

as I can see, compilation process has no issues, though when I'm viewing resulted code in the browser I don't see anything running, no console.log statements are being triggered to the console. bundle.js itself is loading in the network tab with a status of 200 so I assume SystemJS requesting it and loading the contents correctly, but how can I trigger Main module? I also tried to use system type modules but it gave the same result.

like image 848
Andrew Bogdanov Avatar asked Aug 09 '17 15:08

Andrew Bogdanov


1 Answers

The problem

When you do SystemJS.import('bundle.js'); SystemJS makes a path of of the module name by using baseURL, which is /js/bundle.js and issues a GET HTTP request to fetch that. Once it is fetched, it looks for a module named bundle.js inside the bundle, and does not find it. You have two modules, named Ball and Main. (If first argument to AMD's define call is a string, that's the module name.) So you have to use one of these module names.

The solution

SystemJS will search for the module Main if you do SystemJS.import("Main"). However, by default, SystemJS will create a path for Main in the same way it does for bundle.js. Main is not in /js/Main but in /js/bundle.js. So how to tell SystemJS to fetch it from the right place? You have to use the bundles configuration option:

SystemJS.config({
    baseURL: "/js",
    bundles: {
        "bundle.js": ["Main"],
    },
});
SystemJS.import("Main");

The configuration above says "the bundle named bundle.js contains the module Main". (I could have also listed Ball in the array but that's not necessary in this case.) So when you do SystemJS.import("Main"), SystemJS fetches the module named bundle.js from /js/bundle.js and looks in it for the module named Main.

like image 59
Louis Avatar answered Nov 17 '22 16:11

Louis