Executing a module from a bundled file using SystemJS and TypeScript
Asked Answered
M

1

7

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.

Maxey answered 9/8, 2017 at 15:37 Comment(0)
D
6

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.

Darlenedarline answered 9/8, 2017 at 16:16 Comment(4)
Thanks a lot for a detailed explanation of the solution, it really made me understand the gist of the problem. And the solution did work out! ThanksMaxey
Thank you, I was importing my bundle.js with a <script> tag, so nothing was being executed.Belgrade
This seems like what I need, but unfortunately I'm getting ReferenceError: SystemJS is not defined. If I try with just System instead of SystemJS I'm getting TypeError: System.config is not a functionDiorama
@JesseBusman You should check to make sure that SystemJS is actually loaded before you try to access it. Make sure that your browser is fetching it and there's no error. You can do that by checking the network requests in the debugger.Darlenedarline

© 2022 - 2024 — McMap. All rights reserved.