title: Given ES2015, dependency injection and library abstraction, what should my ideal module look like in 2016?
body: <p>If not, for one thing, I would be all on board for writing all of my modules like</p>
  
  <pre><code>import A from './a.js';
  
  var B = function(){
    //use A
  };
  
  export default B;
  </code></pre>
  
  <p>and then using a compiler to build that into some browser or server format.</p>
  
  <p>My one issue with the above however is the explicit specification of <code>./a.js</code> in the <code>import</code>.</p>
  
  <p>I understand why the spec went this way<sup>1</sup>, to be in favour of <a href="https://stackoverflow.com/a/33088650/389765">static analysis</a>. But there are two very practical reasons why baking in both a module's <strong>filename</strong> and its <strong>path</strong> are trouble.</p>
  
  <ol>
  <li>As <a href="https://stackoverflow.com/q/28798747/389765">already raised here</a>, when recycling modules frequently from project to project, it's very likely you won't be able to maintain a consistent <strong>path</strong> to that resource in your project tree. Baking an import call like <code>import myModule from './../../vendor/lib/dist/mod.js'</code> into a module's code doesn't exactly feel future-proof to me.</li>
  <li><p>Besides the path itself, specifying the <strong>filename</strong> also ties you down. Something like this seems innocent enough:</p>
  
  <p><code>import $ from 'vendor/jquery.js'</code></p>
  
  <p>But what about the day when I want to use <a href="http://zeptojs.com/" rel="nofollow noreferrer">Zepto</a> instead of <a href="https://jquery.com/" rel="nofollow noreferrer">jQuery</a>? I've found abstraction, particularly around vendor libraries, to be immensely useful when dealing with large codebases, opinionated developers, and an ever-changing JavaScript ecosystem. I may want to import <a href="https://facebook.github.io/react/" rel="nofollow noreferrer">React</a> as my component library today, but what about tomorrow? Moreover, what if I'm going to be using the same module on both the client and server, but I need different versions of a dependent library?</p></li>
  </ol>
  
  <p>I insist on robust (but clear and consistent) abstraction in my teams. Often times, abstraction has taken the form of some kind of namespacing. I fantasize a bit about this:</p>
  
  <pre><code>//BAD: Bakes React into my component modules
  import ComponentLib from './React.js';
  
  //GOOD: Leaves me free to use any React-like library
  import ComponentLib from 'vendor.lib.component';
  </code></pre>
  
  <p>Where <code>vendor.lib.component</code>, in a Java-like way, has been registered somewhere previously.</p>
  
  <p>Note that <a href="https://stackoverflow.com/q/35914712/389765">unlike in this question</a>, my aim is not to have dynamic control over my imports. I don't want run-time flexibility, I'd like <em>build-time</em> flexibility. I should be able to sub-out a dependent framework for another one, or for a mock, or for something that will work in a particular environment, without having to worry about what dependencies my modules are calling, or trying to duplicate some crazy directory tree for every build product I'm after.</p>
  
  <p>Similar questions have led to the suggestion of a library that leverages the <a href="https://github.com/ModuleLoader/es6-module-loader/blob/master/docs/system-register.md" rel="nofollow noreferrer">System specification</a>, like <a href="https://github.com/systemjs/systemjs" rel="nofollow noreferrer">SystemJS</a>. You can then use something like <a href="http://jspm.io/" rel="nofollow noreferrer">jspm</a> to introduce a module map to get abstraction. But the moment I do that, I'm writing all of my modules differently:</p>
  
  <pre><code>System.import('a', function(A){
    //use 'A'
  });
  </code></pre>
  
  <p>Is that suddenly the future? If so, why don't I just keep using AMD? Why even bother with ES2015 modules and running transpilers if I'm just going to go back to using an asynchronous-looking loader API?</p>
  
  <p>More eye-rolling, I don't see much or any mention of tackling a module loader API standard in the <a href="https://tc39.github.io/ecma262/" rel="nofollow noreferrer">ES2017 spec</a>.</p>
  
  <p>(<em>EDIT: Question revised to meet standards of a non-opinion-based answer</em>)</p>
  
  <p>Given all of the above, I'm asking the community -- how do I write a JavaScript module that (i) abides by the ES2015 standard, (ii) does not reference a dependent module by its filename or path, and (iii) does not rely on extensive intermediate tools/configuration that would make sharing the module with multiple teams prohibitive.</p>
  
  <p>--</p>
  
  <p><strong>Note 1</strong> As @zeroflagL noted in the comments, the spec doesn't explicitly state that a module should be specified as a path, just a string (see <em>ModuleSpecifier</em> - <a href="http://www.ecma-international.org/ecma-262/6.0/#table-41" rel="nofollow noreferrer">http://www.ecma-international.org/ecma-262/6.0/#table-41</a>). However, there is also a clear instruction to account for circular references, implying some kind of static analysis (<a href="http://www.ecma-international.org/ecma-262/6.0/#sec-imports" rel="nofollow noreferrer">http://www.ecma-international.org/ecma-262/6.0/#sec-imports</a>), with file paths seemingly being the reference context of choice to this point. So we can't blame the spec for being rigid here, rather the opposite. The onus may then be on the rest of us to develop more robust implementations of <code>import</code>/<em>ModuleSpecifier</em> that lead to a secondary standard.</p>