{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/5787","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/5787/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/5787/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/5787/events","html_url":"https://github.com/Microsoft/TypeScript/issues/5787","id":118793022,"number":5787,"title":"Better support for loader plugins","user":{"login":"kitsonk","id":1282577,"avatar_url":"https://avatars.githubusercontent.com/u/1282577?v=3","gravatar_id":"","url":"https://api.github.com/users/kitsonk","html_url":"https://github.com/kitsonk","followers_url":"https://api.github.com/users/kitsonk/followers","following_url":"https://api.github.com/users/kitsonk/following{/other_user}","gists_url":"https://api.github.com/users/kitsonk/gists{/gist_id}","starred_url":"https://api.github.com/users/kitsonk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kitsonk/subscriptions","organizations_url":"https://api.github.com/users/kitsonk/orgs","repos_url":"https://api.github.com/users/kitsonk/repos","events_url":"https://api.github.com/users/kitsonk/events{/privacy}","received_events_url":"https://api.github.com/users/kitsonk/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Needs%20Proposal","name":"Needs Proposal","color":"556b75"},{"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Suggestion","name":"Suggestion","color":"006b75"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-11-25T09:20:57Z","updated_at":"2015-12-01T20:04:45Z","closed_at":null,"body":"Currently TypeScript does not have a good understanding of loader plugins.  Both AMD and SystemJS support the concept of loader plugins (though they vary in format).  Currently the only way to integrate a loader plugin is specify the full module name as an ambient declaration and describe the shape of what is returned.  For some plugins, this is quite a redundant activity (like a text plugin) since all resources returned by the plugin are text resources.\r\n\r\nBoth with AMD and SystemJS (also proposed for ES6 module loader), plugins do not have to return a consistent shape.  Because of this, I think there are two approaches:\r\n\r\n1. Create resolution logic that supports some sort of glob pattern for ambient declarations, with resolution of the most specific declaration.\r\n1. Integrate more robust functionality in understanding plugins and what shape they return.\r\n\r\nFor background reading here is the specification of each:\r\n\r\n* [SystemJS/proposed ES6](https://github.com/systemjs/systemjs/blob/master/docs/creating-plugins.md)\r\n* [AMD](https://github.com/amdjs/amdjs-api/blob/master/LoaderPlugins.md)\r\n\r\nFor SystemJS there are four methods that can be overridden the are exposed by the plugin module:\r\n\r\n* `locate` - Allows a return of an alternative location for the resource.\r\n* `fetch` - Allows the plugin to fetch the \"raw\" resource.\r\n* `translate` - Allows the plugin to modify the resource (e.g. translate on the fly from CoffeeScript to JS)\r\n* `instantiate` - Called when the loader actually tries to instantiate the module.\r\n\r\nFor AMD there:\r\n\r\n* `normalize` - Allows the resource ID to be modified\r\n* `load` - Allows hooking into the actual load and instantiation of the module\r\n\r\nRequireJS has support for a couple more, which are specifically geared for building code, but they are not officially part of the AMD standard:\r\n\r\n* `write` - Write out the module\r\n* `onLayerEnd` - Allows a hook into when a layer is finished\r\n* `writeFile` - Hook when the file is written\r\n* `pluginBuilder` - Substitute another module for this module when doing a build\r\n\r\nAlso there is a big difference between AMD and SystemJS in the format of the MID for plugins, annoyingly (I won't get on my soap box about how we reinvent the wheel in on the web).  AMD is `[plugin]![resource]` and SystemJS is `[resource]![plugin]`.\r\n\r\n@mhegazy asked if plugins change their shape.  My personal experience is with AMD and in that case, in practice, some plugins do change their shape (for example in Dojo we have a module that loads CommonJS modules called `dojo/node`) and others that never change their shape (for example `dojo/text` loads text resources) and ones where the resource ID determines what is loaded (for example `dojo/has` take a feature flag and a ternary operator to determine what it loads).\r\n\r\nMy personal feeling is that option 2 would be horribly complex, likely to have all sorts of edge cases, and while highly useful for those using plug-ins, might just become too challenging.  If/when the ES6 Loader is finalised and there is plugin support in there, then having a feature rich analysis of those plugins might be worth the effort.  Until then, I think option 1 would allow people to achieve the most use cases with a minimum amount of complexity.\r\n\r\nThis is related to a discussion that came up in #5759."},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/161080152","html_url":"https://github.com/Microsoft/TypeScript/issues/5787#issuecomment-161080152","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/5787","id":161080152,"user":{"login":"mhegazy","id":8000722,"avatar_url":"https://avatars.githubusercontent.com/u/8000722?v=3","gravatar_id":"","url":"https://api.github.com/users/mhegazy","html_url":"https://github.com/mhegazy","followers_url":"https://api.github.com/users/mhegazy/followers","following_url":"https://api.github.com/users/mhegazy/following{/other_user}","gists_url":"https://api.github.com/users/mhegazy/gists{/gist_id}","starred_url":"https://api.github.com/users/mhegazy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mhegazy/subscriptions","organizations_url":"https://api.github.com/users/mhegazy/orgs","repos_url":"https://api.github.com/users/mhegazy/repos","events_url":"https://api.github.com/users/mhegazy/events{/privacy}","received_events_url":"https://api.github.com/users/mhegazy/received_events","type":"User","site_admin":false},"created_at":"2015-12-01T20:04:45Z","updated_at":"2015-12-01T20:04:45Z","body":"that is not too bad. this is can be 2 extra lookups for failed module imports with a bang in them.. so in resolveExternalModuleName:\r\n\r\n```ts\r\n            if (!isRelative) {\r\n                const symbol = getSymbol(globals, \"\\\"\" + moduleName + \"\\\"\", SymbolFlags.ValueModule);\r\n                if (symbol) {\r\n                    return symbol;\r\n                }\r\n                // Add handling for module loader extensions\r\n                if (moduleName.indexOf(\"!\") >= 0) {\r\n                    let parts = moduleName.split(\"!\", 2);\r\n                    const symbol = getSymbol(globals, \"\\\"\" + parts[0] + \"*\" + \"\\\"\", SymbolFlags.ValueModule) ||\r\n                        getSymbol(globals, \"\\\"\" + \"*\" + parts[1] + \"\\\"\", SymbolFlags.ValueModule);\r\n                    if (symbol) {\r\n                        return symbol;\r\n                    }\r\n                }\r\n            }\r\n```"}}