Modules

  • Revision slug: CommonJS/Modules
  • Revision title: Modules
  • Revision id: 93379
  • Created:
  • Creator: Petermichaux
  • Is current revision? No
  • Comment no wording changes

Revision Content

To date, client side JavaScript has generally been able to get away with something as simple as the <script> tag and no standard way to do namespaces. On the server, it's a bit different because you're more likely to use more libraries and you can potentially load up a lot of code. Having a basic system for loading code and encouraging the use of namespaces to avoid unintentional interference will underlie everything else.

Prior Art

  • Spidermonkey (and Jaxer) and Rhino offer a load function, but does not have any specific pattern for namespacing.
  • Dojo has a complete incremental loading facility in the form of dojo.require and a standard mechanism for declaring modules. dojo.require ensures that the module is loaded only once. It also manages dependecies between modules.
  • The Jack project implements a simple "require" system.
  • Persevere uses "require" (similar to Jack) for module loading.
  • Helma NG implements a module system with per-module scopes and import, include and require functions.
  • jslibs bootstrapping jshost provides only basic code and loading module support, direct from file and either into the global namespace or a chosen namespace http://code.google.com/p/jslibs/wiki/jshost
  • Advanced JavaScript Importing & Loading Extension is the browser-independent extension that provides Javascript with namespace and dynamic script loading support ( http://ajile.iskitz.com/ )
  • modulesjs an XHR JS module loader provides module loading, singleton modules ( http://modulesjs.com/
  • Synchronet provides a global load() method which allows a specified scope/sandbox object, passing arguments, and background/concurrent execution: http://synchro.net/docs/jsobjs.html#global
  • Ejscript has a loadable module mechanism based on language extensions "module" and "use module" definitions. Modules can have scope, dependencies, incremental loading and optional backing native code.

Proposed API

 

P1) global file loading

The following is a simple system based on loading files by filename. This is quite Ruby-like.

 
//
// Evaluate the content of the fully specified file
// in the global scope.
//
load('/usr/local/lib/js/File.js')

//
// If no file extension is included '.js' is assumed
//
load('/usr/local/lib/js/File')

//
// Searching through the library path.
// Suppose the path is
// /home/peter/js:/usr/local/lib/js:/usr/lib/js
//
load('File')

//
// Use 'load' above only if this file has never been
// loaded before.
//
load.once('File')

//
// Load a file relative to the current file's path.
// '__DIR__' is a macro expanded to the file's absolute path
// before the code is evaluated. It may be that __DIR__ is
// expanded to be something like
//
// /home/peter/src/foo-project
//
// This allows for one file to load many others distributed
// in the same package.
//
// web-framework.js
// web-framework/
// routing.js
// templates.js
// orm.js
//
// This does not cross over to the browser as the browser does
// not have macros.
//
load(__DIR__+'subdir/foo');

 Remark: the __DIR__ macro is not necessary: the JS intepreter can as well do a chdir() to the directory of a script being loaded, effectively setting a new base path for consecutive relative includes.

Remark: I think chdir() is not a good option here because if one module does chdir to include other modules which also do chdir(), then chdir() is required before every individual "load". Otherwise the current directory is basically unknown to any particular script. -- Peter Michaux

P2) global object loading

A system similar to the simple file loading as file content is still evaluated in the global scope; however, this system depends on a naming convention between file and object names. This makes it a bit more Java-like and is more heavily dependent on the library path. It removes the need to think about a file system and makes it possible to use the same system in the browser.

 
//
// Searching through the library path.
// Suppose the path is
// /home/peter/js:/usr/local/lib/js:/usr/lib/js
// Then if can evaluate the content of the file
// /usr/local/lib/js/io/File.js in the global scope
// with
load('io.File')

//
// Use 'load' above only if this file has never been
// loaded before.
//
load.once('io.File')

P3) Pythonic Modules

This is a proposal that provides protection against name collisions by isolating module scopes, while being reasonably easy to implement in a server or standalone JavaScript runtime.

P4) Securable Modules

This is a proposal that provides protection against name collisions by isolating module scopes, defaults declarations to closure private scope, and emphasizes interoperability on three dimensions: client to server, insecure to secure, and current to future.

Related discussions

Revision Source

<p>To date, client side JavaScript has generally been able to get away with something as simple as the &lt;script&gt; tag and no standard way to do namespaces. On the server, it's a bit different because you're more likely to use more libraries and you can potentially load up a lot of code. Having a basic system for loading code and encouraging the use of namespaces to avoid unintentional interference will underlie everything else.</p>
<h3>Prior Art</h3>
<ul> <li>Spidermonkey (and Jaxer) and Rhino offer a <a class="external" href="/En/SpiderMonkey/Introduction_to_the_JavaScript_shell" title="https://developer.mozilla.org/editor/fckeditor/core/editor/en/Introduction_to_the_JavaScript_shell">load</a> function, but does not have any specific pattern for namespacing.</li> <li>Dojo has a complete incremental loading facility in the form of <a class="external" href="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/functions-used-everywhere/dojo-require" title="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/functions-used-everywhere/dojo-require">dojo.require</a> and a standard mechanism for declaring modules. dojo.require ensures that the module is loaded only once. It also manages dependecies between modules.</li> <li>The Jack project <a class="external" href="http://github.com/tlrobinson/jack/blob/54a28398425287bddd9466955d5e8ea616eb8d47/core.js" title="http://github.com/tlrobinson/jack/blob/54a28398425287bddd9466955d5e8ea616eb8d47/core.js">implements a simple "require" system</a>.</li> <li><a class="external" href="http://docs.persvr.org/documentation/server-side-js" title="http://docs.persvr.org/documentation/server-side-js">Persevere uses "require"</a> (similar to Jack) for module loading.</li> <li>Helma NG implements a <a class="external" href="http://dev.helma.org/ng/Modules+and+Scopes/" title="http://dev.helma.org/ng/Modules+and+Scopes/">module system</a> with per-module scopes and import, include and require functions.</li> <li>jslibs bootstrapping jshost provides only basic code and loading module support, direct from file and either into the global namespace or a chosen namespace <a class=" external" href="http://code.google.com/p/jslibs/wiki/jshost" rel="freelink">http://code.google.com/p/jslibs/wiki/jshost</a></li> <li><strong>A</strong>dvanced <strong>J</strong>avaScript <strong>I</strong>mporting &amp; <strong>L</strong>oading <strong>E</strong>xtension is the browser-independent extension that provides Javascript with namespace and dynamic script loading support ( <a class=" external" href="http://ajile.iskitz.com/" rel="freelink">http://ajile.iskitz.com/</a> )</li> <li>modulesjs an XHR JS module loader provides module loading, singleton modules ( <a class=" external" href="http://modulesjs.com/" rel="freelink">http://modulesjs.com/</a> ) </li> <li><a class="external" href="http://synchro.net" title="http://synchro.net">Synchronet</a> provides a global <em>load()</em> method which allows a specified scope/sandbox object, passing arguments, and background/concurrent execution: <a class="external" href="http://synchro.net/docs/jsobjs.html#global">http://synchro.net/docs/jsobjs.html#global</a></li> <li><a class="external" href="http://www.ejscript.org/" title="http://www.ejscript.org/">Ejscript</a> has a loadable module mechanism based on language extensions "module" and "use module" definitions. Modules can have scope, dependencies, incremental loading and optional backing native code.</li>
</ul>
<h3>Proposed API</h3>
<p> </p>
<h4 id="simple-file-loading">P1) global file loading</h4>
<p>The following is a simple system based on loading files by filename. This is quite Ruby-like.</p>
<pre><code> <br>//<br>// Evaluate the content of the fully specified file <br>// in the global scope. <br>// <br>load('/usr/local/lib/js/File.js')  <br><br>// <br>// If no file extension is included '.js' is assumed <br>// <br>load('/usr/local/lib/js/File')  <br><br>// <br>// Searching through the library path.  <br>// Suppose the path is <br>// /home/peter/js:/usr/local/lib/js:/usr/lib/js <br>//  <br>load('File')  <br><br>// <br>// Use 'load' above only if this file has never been <br>// loaded before. <br>// <br>load.once('File')  <br><br>//  <br>// Load a file relative to the current file's path. <br>// '__DIR__' is a macro expanded to the file's absolute path <br>// before the code is evaluated. It may be that __DIR__ is <br>// expanded to be something like <br>// <br>//    /home/peter/src/foo-project  <br>// <br>// This allows for one file to load many others distributed <br>// in the same package. <br>// <br>//    web-framework.js <br>//    web-framework/ <br>//      routing.js <br>//      templates.js <br>//      orm.js <br>// <br>// This does not cross over to the browser as the browser does <br>// not have macros. <br>//<br>load(__DIR__+'subdir/foo'); </code></pre>
<p> Remark: the __DIR__ macro is not necessary: the JS intepreter can as well do a chdir() to the directory of a script being loaded, effectively setting a new base path for consecutive relative includes.</p>
<p>Remark: I think chdir() is not a good option here because if one module does chdir to include other modules which also do chdir(), then chdir() is required before every individual "load". Otherwise the current directory is basically unknown to any particular script. -- Peter Michaux</p>
<h4 id="simple-object-loading">P2) global object loading</h4>
<p>A system similar to the simple file loading as file content is still evaluated in the global scope; however, this system depends on a naming convention between file and object names. This makes it a bit more Java-like and is more heavily dependent on the library path. It removes the need to think about a file system and makes it possible to use the same system in the browser.</p>
<pre><code> <br> // <br> // Searching through the library path.  <br> // Suppose the path is <br> // /home/peter/js:/usr/local/lib/js:/usr/lib/js <br> // Then if can evaluate the content of the file <br> // /usr/local/lib/js/io/File.js in the global scope <br> // with<br> load('io.File')  <br> <br> // <br> // Use 'load' above only if this file has never been <br> // loaded before. <br> // <br> load.once('io.File')  <br> <br> </code></pre>
<h4>P3) <a class="internal" href="/ServerJS/Modules/Pythonic_Modules" title="ServerJS/Modules/Pythonic Modules">Pythonic Modules</a></h4>
<p>This is a proposal that provides protection against name collisions by isolating module scopes, while being reasonably easy to implement in a server or standalone JavaScript runtime.</p>
<h4>P4) <a class="internal" href="/ServerJS/Modules/Securable_Modules" title="ServerJS/Modules/Securable Modules">Securable Modules</a></h4>
<p>This is a proposal that provides protection against name collisions by isolating module scopes, defaults declarations to closure private scope, and emphasizes interoperability on three dimensions: client to server, insecure to secure, and current to future.</p>
<h3>Related discussions</h3>
<ul> <li><a class="external" href="http://groups.google.com/group/serverjs/browse_thread/thread/d761996c25769e6c">"a module system (difficult to agree)"</a></li> <li><a class="external" href="http://groups.google.com/group/serverjs/browse_frm/thread/b99a5b6eb9ed8a23"> Concerns about the proposed module system(s) </a></li> <li><a class="external" href="http://groups.google.com/group/serverjs/browse_frm/thread/2dcfbff6b6ba5928"> do we need a Module object instead of require() function? </a></li> <li><a class="external" href="http://groups.google.com/group/serverjs/browse_frm/thread/1abef605cf13c337"> Are we agreed on require, in general? </a></li>
</ul>
Revert to this revision