Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Omit "require" and "exports" from TypeScript emitted AMD dependencies

Tags:

typescript

amd

Given the following TypeScript file,

export = {};

tsc (with "module": "amd") will emit:

define(["require", "exports"], function (require, exports) {
  "use strict";
   return {};
});

However, I would rather it emit

define([], function() {
    "use strict";
    return {};
});

... and only include require or exports if I explicitly import them, i.e.

import relativeRequire = require("require");

Is there any way to tell TypeScript not to emit require and exports in emitted AMD modules (i.e. ask it not to use the CommonJS simplified wrapping)?

Notes:

  • The output I propose is fully compliant with the AMD spec.
  • An empty dependencies array is the only way for the module to have zero dependencies (as opposed to omitting the dependencies array, which implies the require, exports, and module dependencies).

UPDATE 4 July 2017: Looks like this is actually an open issue in the TypeScript GitHub repo: https://github.com/Microsoft/TypeScript/issues/669

Any ideas for a pragmatic workaround until this gets implemented? (Or, is there actually some way to make TypeScript do this?)

like image 642
Roy Tinker Avatar asked Jun 29 '17 22:06

Roy Tinker


2 Answers

I see no substantial advantage in what you are trying to do. Whatever execution time is saved by removing the unused dependencies will be dwarfed by the execution time of the rest of the app, for any app that is more than a toy app. Both require and exports are virtual modules that cost very little to instantiate. (By "virtual" I mean they are completely internal to the AMD loader you use and do not entail any fetching from the network or a file on disk.) I see issue 669 you mention has been open since September 2014 and deemed "accepted" since April 2015. No one seems to be hurting so badly that they are rushing to produce a pull request.

I don't know of any way TypeScript will do what you want out of the box. I recently researched how TypeScript emits its define calls because I needed to add the virtual module named "module" to the list of dependencies. (If you use Angular, you want to use module.id to pass the id of the current module to Angular so that it can resolve things like relative template paths, etc. You can use module.id without issue with CommonJS output but with AMD output module is not included by default in the list of dependencies.) I worked around the issue by writing a build step that modifies the code that tsc emits, after tsc has emitted it. It uses a regexp that modifies the dependency list to add "module", and modifies the callback to add the corresponding argument. This works for me because I'm adding. It is not a good enough approach for what you are trying to do because you want to remove dependencies but there may be cases where removing them would result in invalid code.

For a workaround, you could use Esprima to examine the JavaScript generated by tsc and if the values of the modules "require" and "exports" are not used by the code inside the factory function passed to define, then remove the unused modules from the dependency list and the corresponding arguments from the argument list passed to the factory function. This would be the most general solution. (Among other things, it would be compatible with using the asynchronous require call that AMD loaders make available (of the form require([...], function (...) {})) inside the factory function.) But coding this logic may be just as involved as it would be to produce a pull request have tsc emit the code you want in the first place.

like image 194
Louis Avatar answered Nov 06 '22 06:11

Louis


Require

You said:

.. and only include require or exports if I explicitly import them, i.e. import relativeRequire = require("require");

You can't use require unless its already there. So its good that its there.

Exports

exports is needed as soon as you export something. If you want to have a root export as in export = then TypeScript maps it to return. But with export const foo = 123 it would need to use exports.

There is no harm in it being there and any performance impact is truly minimal.

like image 44
basarat Avatar answered Nov 06 '22 07:11

basarat