7

I've being trying to bundle my TypeScript "application" into a single javascript file.

I'm not using any bundler but TSC ( using TypeScript 2.2 ). Aside of my own ts files, my application also uses external modules such immutablejs.

I read every possible thread, documentation but I can't find a way to bundle external modules ( from node_modules ) into my compiled / transpiled javascript file using only TSC.

Down below you can find a sample of my latest code/ configu as well as the results of my attempts.

tsconfig.json

{
    "compilerOptions": {
        "target":           "es5",
        "module":           "system",
        "removeComments":   true,
        "sourceMap":        true,
        "allowJs":          true
    }
}

app.ts - note: ./something.ts is successfully bundled.

/// <reference path="../node_modules/immutable/dist/immutable.d.ts" />

import * as something from "./something";
import * as Immutable  from "immutable";

console.log( something.test );

const map1 = Immutable.Map( { a: 1, b: '2', c: 'cu' });
console.log( map1.get( 'a') )

1#: using tsc-bundle (https://www.npmjs.com/package/typescript-bundle)

This method not only don't bundle immutableJs as well as thrown the error: require is not defined.

var dragonfly = (function () {
  var main = null;
  var modules = {
      "require": {
          factory: undefined,
          dependencies: [],
          exports: function (args, callback) { return require(args, callback); },
          resolved: true
      }
  };
  function define(id, dependencies, factory) {
      return main = modules[id] = {
          dependencies: dependencies,
          factory: factory,
          exports: {},
          resolved: false
      };
  }
  function resolve(definition) {
      if (definition.resolved === true)
          return;
      definition.resolved = true;
      var dependencies = definition.dependencies.map(function (id) {
          return (id === "exports")
              ? definition.exports
              : (function () {
                  if(modules[id] !== undefined) {
                    resolve(modules[id]);
                    return modules[id].exports;
                  } else return require(id)
              })();
      });
      definition.factory.apply(null, dependencies);
  }
  function collect() {
      Object.keys(modules).map(function (key) { return modules[key]; }).forEach(resolve);
      return (main !== null) 
        ? main.exports
        : undefined
  }

  define("something", ["require", "exports"], function (require, exports) {
      "use strict";
      Object.defineProperty(exports, "__esModule", { value: true });
      exports.test = "oie";
  });
  define("app", ["require", "exports", "something", "immutable"], function (require, exports, something, Immutable) {
      "use strict";
      Object.defineProperty(exports, "__esModule", { value: true });
      console.log(something.test);
      var map1 = Immutable.Map({ a: 1, b: '2', c: 'cu' });
      console.log(map1.get('a'));
  });
  //# sourceMappingURL=app.js.map
  return collect(); 
})();

#2 - using TSC with module = system ( tsc src/app.ts -m system --outfile build/app.js )

This method also don't bundle immutableJs but also thrown the error: System is not defined

System.register("something", [], function (exports_1, context_1) {
    "use strict";
    var __moduleName = context_1 && context_1.id;
    var test;
    return {
        setters: [],
        execute: function () {
            exports_1("test", test = "oie");
        }
    };
});
/// <reference path="../node_modules/immutable/dist/immutable.d.ts" />
System.register("app", ["something", "immutable"], function (exports_2, context_2) {
    "use strict";
    var __moduleName = context_2 && context_2.id;
    var something, Immutable, map1;
    return {
        setters: [
            function (something_1) {
                something = something_1;
            },
            function (Immutable_1) {
                Immutable = Immutable_1;
            }
        ],
        execute: function () {/// <reference path="../node_modules/immutable/dist/immutable.d.ts" />
            console.log(something.test);
            map1 = Immutable.Map({ a: 1, b: '2', c: 'cu' });
            console.log(map1.get('a'));
        }
    };
});

#3 - using tsc with module = amd ( tsc src/app.ts -m amd --outfile build/app.js )

This method not only don't bundle immutableJs as well as thrown the error: define is not defined.

define("something", ["require", "exports"], function (require, exports) {
    "use strict";
    exports.__esModule = true;
    exports.test = "oie";
});
/// <reference path="../node_modules/immutable/dist/immutable.d.ts" />
define("app", ["require", "exports", "something", "immutable"], function (require, exports, something, Immutable) {
    "use strict";
    exports.__esModule = true;
    console.log(something.test);
    var map1 = Immutable.Map({ a: 1, b: '2', c: 'cu' });
    console.log(map1.get('a'));
});

Conclusion: It's really important for the future of my project be able to bundle external libraries without the need of these popular bundlers such as webpack, browserify, gulp, etc...

Does anyone can help me?

Thanks in advance,

TF!

Tito Facchini
  • 115
  • 2
  • 4
  • Just curious - is there a reason why you reject webpack and browserify but are willing to use relatively unknown [typescript-bundle](https://github.com/sinclairzx81/typescript-bundle)? As you have seen, typescript is not a bundler, it will not include external dependencies in the output, unless they are all compiled together at the same time with your own code. – artem Apr 17 '17 at 19:59
  • Hi Artem, thanks for the answer... The reason why I'm rejecting is only one. I have to use the webserver / watcher / task runner I created, do you think would still be a good idea / possible use one of these guys ( webpack, gulp, bower ) only as bundler? – Tito Facchini Apr 18 '17 at 04:26
  • If you need only the bundler, then webpack with [ts-loader](https://github.com/TypeStrong/ts-loader) is the most obvious choice - you don't need anything else besides that. I also have used [systemjs-builder](https://github.com/systemjs/builder) for bundling, and know that some people are using [rollup](https://rollupjs.org/) – artem Apr 18 '17 at 05:33
  • Thanks again for the answer... I had a look in the systemjs-builder, and looked pretty straight forward. Question though is: How you consume the JS from the browser? I mean how can I use the bundle? is it exposed at window object level? – Tito Facchini Apr 18 '17 at 06:19
  • Also how it would work with Typescript? I would need to firstly compile ts into js and then run trigger the bundler? – Tito Facchini Apr 18 '17 at 06:34
  • It depends on the module loader that you have in the browser. With webpack, you have self-contained bundle having your app and all dependencies, and load it with script tag which executes main module. For systemjs builder, you are supposed to use SystemJS and you can load your modules like `System.import('your-app').then(appModule => {...})`. With typescript, you can compile first and bundle `.js` files, or you can use [ts-loader](https://github.com/TypeStrong/ts-loader) for webpack or [plugin-typescript](https://github.com/frankwallis/plugin-typescript/) for SystemJS to bundle `.ts` files. – artem Apr 18 '17 at 06:41

1 Answers1

1

Just noticed your post, and disclaimer, I am the author of typescript-bundle. You can bundle ImmutableJS with the following.

tsc-bundle --project ./tsconfig.json --importAs immutable=Immutable

Some documentation about this switch here

This will create an additional resolver that attempts to resolve immutable from the window object. This is typically the case if you are including dependant scripts in your page (via a <script> tag) and need that global name (Immutable in this case) referenced in your bundle (and you need to make use of .d.ts files pulled from @types/* with the ambient module named "immutable")

The above line results in the following resolve() function.

  function resolve(definition) {
      if (definition.resolved === true)
          return;
      definition.resolved = true;
      var dependencies = definition.dependencies.map(function (id) {
          return (id === "exports")
              ? definition.exports
              : (function () {
                  if(modules[id] !== undefined) {
                    resolve(modules[id]);
                    return modules[id].exports;
                  } else if(id === "immutable") {
                    return window["Immutable"];
                  } else {
                    try {
                      return require(id);
                    } catch(e) {
                      throw Error("module '" + id + "' not found.");
                    }
                  }
              })();
      });
      definition.factory.apply(null, dependencies);
  }

This works against most declarations you will find in the npm @types/* repository (assumed UMD) and allows the bundle to effectively pull the module from the environment (global variable name).

Hope you find this helpful

sinclairzx81
  • 81
  • 1
  • 2