Search code examples
javascriptangularjstypescriptrequirejsumd

Import is ignored on require.js by migrating old AngularJS to TypeScript


I want to migrate my old AngularJS application from JavaScript to TypeScript. For loading the requirements I'm using require.js. And because I want to be compatible with the non-require.js scripts I'm using umd as module.

For example I have this files.

customModule.ts

import angular = require('angular');

angular.module('customModule', []);

main.ts

import angular = require('angular');
import customModule = require('customModule');

angular
    .module('app')
    .factory('customFactory', ['customModule', class {
        constructor(
            private customModule
        ) { }

        out() {
            return this.customModule;
        };
    }]);

This will be converted to this JavaScript.

customModule.js

(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", "angular"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var angular = require("angular");
    angular.module('customModule', []);
});

main.ts

(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", "angular"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var angular = require("angular");
    angular
        .module('app')
        .factory('customFactory', ['customModule', (function () {
            function class_1(customModule) {
                this.customModule = customModule;
            }
            class_1.prototype.out = function () {
                return this.customModule;
            };
            ;
            return class_1;
        }())]);
});

As you can see in the main.js there is a define(["require", "exports", "angular"], factory);. But I expect define(["require", "exports", "angular", "customModule"], factory);.

If I replace return this.customModule; on main.ts with return customModule; it will exports it right but I think then I not need the constructor. - As you can see the changes on the picture I removed the constructor because it's not needed.

Changes of main.js after removing constructor

If this problem is solved I can use my modules with TypeScript as I use them with JavaScript <3


Solution

  • The TypeScript compiler has an optimisation, so if you have the below code, something magic happens...

    import * as angular from 'angular';
    import * as customModule from 'customModule';
    
    angular
        .module('app')
        .factory('customFactory', ['customModule', class {
            constructor(
                private customModule
            ) { }
    
            out() {
                return this.customModule;
            };
        }]);
    

    Because the compiler can't see any reference to anything within customModule, it optimises away the import.

    You can fix it by either using the imported module, or by using a forced import as shown below:

    import * as angular from 'angular';
    import 'customModule'; // <-- FORCED
    
    angular
        .module('app')
        .factory('customFactory', ['customModule', class {
            constructor(
                private customModule
            ) { }
    
            out() {
                return this.customModule;
            };
        }]);