0

I have a tsconfig.json like this:

{
  "compilerOptions": {
    "lib": ["es2017", "dom"],
    "module": "umd",
    "outDir": "dist",
    "target": "es5",
    "declaration": true
  },
  "compileOnSave": true,
  "files": [
    "myClass.ts"
    "demo.ts"
  ]
}

My typescript, demo.ts:

import { MyClass } from './myClass';

(() => {
  console.log('fired IIFE');
  document.onreadystatechange = function () {
    if (document.readyState === 'interactive') {
      console.log('hello world', MyClass);
    }
  };
})();

Which gets compiled to:

(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "./myClass"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var myClass_1 = require("./myClass");
    (function () {
        console.log('fired IIFE');
        document.onreadystatechange = function () {
            if (document.readyState === 'interactive') {
                console.log('hello world', myClass_1.MyClass);
            }
        };
    })();
});

My html:

<!DOCTYPE HTML>
<html>
<head>
  <title>Test</title>
  <script src="./dist/myClass.js"></script>
  <script src="./dist/demo.js"></script>
</head>
<body>
  <p>test</p>
</body>
</html>

I have also tried:

<!DOCTYPE HTML>
<html>
<head>
  <title>Test</title>
</head>
<body>
  <p>test</p>
  <script src="./dist/myClass.js"></script>
  <script src="./dist/demo.js"></script>
</body>
</html>

Neither way executes the script, and neither log statement is printed. What am I doing wrong?

inorganik
  • 24,255
  • 17
  • 90
  • 114
  • What does that TypeScript compile into? That method is inside a UMD module. You'll need to load the module to execute the method. –  Feb 15 '19 at 19:36
  • Are you sure your current demo.ts is gettting compiled into ./dist/demo.js? What does tsc --version give you? – JGFMK Feb 15 '19 at 19:41
  • You may find this useful too, in case typescript wasn't installed globally. https://stackoverflow.com/a/46783952/495157 – JGFMK Feb 15 '19 at 20:08
  • @JGFMK and Amy - apologies, I omitted part of my code because I thought it made no difference - I updated my question. – inorganik Feb 15 '19 at 20:27
  • It should be able from `window.myClass` (I think)? I have limited experience with UMD modules. –  Feb 15 '19 at 20:38
  • @amy the issue is that with teh import `import { MyClass } from './myClass';` at the top of demo.ts, the IIFE never fires because it gets wrapped ina UMD module. Since it is importing `MyClass`, you reference it that way `MyClass` – inorganik Feb 15 '19 at 20:49
  • I haven't used UMD much either - but the fact you said something wasn't working - made me think eliminate the obvious first. From looking here https://github.com/umdjs/umd/issues/124 - have you tried import like so `import './umd-foo.js' ` – JGFMK Feb 15 '19 at 20:50
  • Should I use a different module style? I thought UMD was the most compatible overall – inorganik Feb 15 '19 at 20:51

1 Answers1

0

Turns out you need to use requirejs in order to execute a typescript-generated UMD module:

<!DOCTYPE HTML>
<html>
<head>
  <title>Test</title>
  <script data-main="dist/demo" type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.1/require.min.js"></script>
</head>
<body>
  <p>test</p>
</body>
</html>

What's going on here is that data-main points to the .js file that loads everything else. You don't need to load your class script separately, require.js does that for you.

This threw me because with gulp-wrap-umd package, the wrapper it provided would not create an isolate scope for the enclosed script, it was effectively global, whereas typescript generated UMD wrapped scripts have isolate scopes.

In this implementation my bootstrapping script demo.js looks like this:

(function (factory) {
  if (typeof module === "object" && typeof module.exports === "object") {
      var v = factory(require, exports);
      if (v !== undefined) module.exports = v;
  }
  else if (typeof define === "function" && define.amd) {
      define(["require", "exports", "./myClass"], factory);
  }
})(function (require, exports) {
  "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  require(["./dist/myClass"], (myClassModule) => {

    console.log('my class:', myClassModule.MyClass);
  });

Where the log statement is, you can run any script without needing document.onready... or window.onload.

inorganik
  • 24,255
  • 17
  • 90
  • 114
  • 1
    Glad you solved it - you mentioning require.js sparked memories for me. Had this squirrelled away in my bookmarks. https://www.davidbcalhoun.com/2014/what-is-amd-commonjs-and-umd/ https://github.com/umdjs/umd https://addyosmani.com/writing-modular-js/ – JGFMK Feb 15 '19 at 22:09