Towards a Proposal: Unified Module Specification

13 views
Skip to first unread message

Christoph Dorn

unread,
Oct 19, 2010, 12:07:59 PM10/19/10
to comm...@googlegroups.com
Goal:

A module source format that works natively on the server and browser
*and supports necessary browser loading intricacies*.


Base Format:

define(function(require, exports, module) {
var bar = require('bar'),
baz = require("baz");
});

Requires scraping for require()'s (already a requirement for 'lean'
deployment of Modules/1.1)


Extended Format:

define([
"bar",
"baz"
],
function(require, exports, module) {
var bar = require('bar'),
baz = require("baz");
});

Used for more complex modules where scraping is error prone.

This assumes one module per source file. Let's leave the async and
multi-module transport aspects out of this discussion. They can be
addresses subsequently.

I believe this addresses all the core issues at hand.

Please keep arguments specific and do now throw blankets. Let's flush
out the pros and cons of this format or slight derivatives thereof.

Christoph

Kevin Dangoor

unread,
Oct 20, 2010, 11:08:45 AM10/20/10
to comm...@googlegroups.com
I haven't seen any replies to this, but there has been a good bit of discussion on the requirements and features of modules.

Having come around in my thinking about the value of serverless operation, I think Christoph's proposal sounds great. The 2 lines of added scaffolding required are not bad and are an *easy* conversion from the current format. I think this format meets all of the requirements that people have for modules at this point (is that not the case?).

I don't presently maintain a module loader, so it would be good if people who do have module loaders they maintain speak up.

Kevin 


--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.




--
Kevin Dangoor

work: http://mozilla.com/
email: k...@blazingthings.com
blog: http://www.BlueSkyOnMars.com

Fabian Jakobs

unread,
Oct 20, 2010, 11:13:55 AM10/20/10
to comm...@googlegroups.com
Most of the problems with the current format boils down to: "Can I
load it with a script tag". This solution allows it and it is a
minimal variation to the current module format. I'm all for it.

Fabian

khs4473

unread,
Oct 20, 2010, 11:20:44 AM10/20/10
to CommonJS
This format is inferior in every situation *except* loading into a
script tag with no transformation.

-1

Please see the "CommonJS Modules - Re-framing the AMD discussion"
thread for my thoughts on resolving this issue.

Wes Garland

unread,
Oct 20, 2010, 11:23:17 AM10/20/10
to comm...@googlegroups.com
On Tue, Oct 19, 2010 at 12:07 PM, Christoph Dorn <christ...@christophdorn.com> wrote:
Goal:

A module source format that works natively on the server and browser *and supports necessary browser loading intricacies*.

That goal can be achieved with the current CJS-MF, provided you either load your modules through XHR, or have a build step (or server application such as FlyScript).

It is also not backwards compatible with CJS-MF, and places additional restrictions on module providers; specially, the option to make the module-scope a "var object", like the window object in a browser, is no longer possible as you are enforcing module load in a lexical var scope.

As such, I would vote against it as I believe it doesn't solve a "real" problem, but rather addresses an artificial constraint railed upon by a vocal minority.

For what's it's worth, though, I think it's a nice transport format.

Wes

--
Wesley W. Garland
Director, Product Development
PageMail, Inc.
+1 613 542 2787 x 102

Rik Arends

unread,
Oct 20, 2010, 11:25:41 AM10/20/10
to comm...@googlegroups.com
I must say this proposal can make me consider a unified format.

+1

I do like the fact that it does not have the requireJS dependency-refs as function arguments (that invites skewing)
But i would try to make scraping-less dependency definition the most common way of doing it.

Rik

Eugene Lazutkin

unread,
Oct 20, 2010, 1:35:14 PM10/20/10
to CommonJS
I don't care about bikeshedding, I care about the functionality. What
you proposed allows to do what I need functionality-wise, so in my
opinion this is clearly a viable option.

Oh, let me state my criteria: ability to load modules in all
reasonable JS environments unchanged (browsers and SSJS included)
without server-side requirements, "compilation" steps, and any other
artificial restrictions like "same-origin" requirements imposed by
XHR.

Cheers,

Eugene

On Oct 19, 9:07 am, Christoph Dorn <christoph...@christophdorn.com>
wrote:

Dean Landolt

unread,
Oct 20, 2010, 1:36:29 PM10/20/10
to comm...@googlegroups.com
On Wed, Oct 20, 2010 at 1:35 PM, Eugene Lazutkin <eugene....@gmail.com> wrote:
I don't care about bikeshedding, I care about the functionality. What
you proposed allows to do what I need functionality-wise, so in my
opinion this is clearly a viable option.

Oh, let me state my criteria: ability to load modules in all
reasonable JS environments unchanged (browsers and SSJS included)
without server-side requirements, "compilation" steps, and any other
artificial restrictions like "same-origin" requirements imposed by
XHR.

So, load from script tags?

Eugene Lazutkin

unread,
Oct 20, 2010, 1:44:26 PM10/20/10
to CommonJS
Inline.

On Oct 20, 10:36 am, Dean Landolt <d...@deanlandolt.com> wrote:
> On Wed, Oct 20, 2010 at 1:35 PM, Eugene Lazutkin
> <eugene.lazut...@gmail.com>wrote:
>
> > I don't care about bikeshedding, I care about the functionality. What
> > you proposed allows to do what I need functionality-wise, so in my
> > opinion this is clearly a viable option.
>
> > Oh, let me state my criteria: ability to load modules in all
> > reasonable JS environments unchanged (browsers and SSJS included)
> > without server-side requirements, "compilation" steps, and any other
> > artificial restrictions like "same-origin" requirements imposed by
> > XHR.
>
> So, load from script tags?

For SSJS platforms? :-) Sorry, couldn't resist.

Answer: no, script tags are not required. If you find a way to satisfy
my criteria with alternative mechanisms --- e.g., encode JS as a GIF
image, WAV file, or any other exotic solutions --- I would be ecstatic
provided they are simple, and do not require huge loaders, or a lot of
CPU.

Cheers,

Eugene

Christoph Dorn

unread,
Oct 20, 2010, 2:12:03 PM10/20/10
to comm...@googlegroups.com

Maybe we need a source format that can bridge the current gap until it
is closed in time through various means.

If the format I am proposing is a strict subset of Modules/1.1.1 in
terms of features, current loaders can be upgraded to support it as an
alternative format (provided the two formats can be easily distinguished
at load time).

Module authors can then choose the bridged format that works on the
server and client while being aware that some restrictions are in place
as opposed to Modules/1.1.1. If the full-feature set is required they
can opt to code in Modules/1.1.1 format and load using inferior
solutions (echoing sentiment from some browser loader implementers
representing the largest userbases we currently have) or converting to a
transport format on the fly.

I am all for the *one* module source format that embodies the best
theory and practice *but* the adoption aspect must not be overlooked or
CommonJS will not gain traction as a browser-*friendly* format.

Let the authors who want to code *pure* stay pure and empower the users
who want *convenience* to use CommonJS Modules *today*, not in a few
years time.

I work server-side and client-side in multiple environments and am all
for good theory and longevity and don't really see an issue to the above
*approach* provided it is technically sound (I am not the one to make
this assessment).

Criteria:

* The bridge format *must* be a feature subset of Modules/1.1.1
* The bridge format *must* convert to Modules/1.1.1 by loaders and
build tools if desired
* Loaders *should* support Modules/1.1.1 *and* the bridge format natively

Christoph

Kris Kowal

unread,
Oct 20, 2010, 2:59:13 PM10/20/10
to comm...@googlegroups.com
On Tue, Oct 19, 2010 at 9:07 AM, Christoph Dorn
<christ...@christophdorn.com> wrote:
> Base Format:
>
>  define(function(require, exports, module) {
>      var bar = require('bar'),
>      baz = require("baz");
>  });
>
>  Requires scraping for require()'s (already a requirement for 'lean'
> deployment of Modules/1.1)
>
>
> Extended Format:
>
>  define([
>    "bar",
>    "baz"
>  ],
>  function(require, exports, module) {
>      var bar = require('bar'),
>      baz = require("baz");
>  });
>
>  Used for more complex modules where scraping is error prone.
>
> This assumes one module per source file. Let's leave the async and
> multi-module transport aspects out of this discussion. They can be addresses
> subsequently.
>
> I believe this addresses all the core issues at hand.

+1. I think that any other features should be implementation-specific.
Let's write this up. I recommend putting it in CommonJS/Scripts to
avoid the Transporter/AMD nomenclature that various people do not
like. I think we should couch it in strong words about philosophy,
vote on it, and move on.

Kris Kowal

khs4473

unread,
Oct 20, 2010, 3:11:21 PM10/20/10
to CommonJS
+1

I'm all for taking a vote and settling the matter. After the vote, I
don't want to hear about it! ; )

Kevin Dangoor

unread,
Oct 20, 2010, 3:14:08 PM10/20/10
to comm...@googlegroups.com
On Wed, Oct 20, 2010 at 2:59 PM, Kris Kowal <kris....@cixar.com> wrote:
+1. I think that any other features should be implementation-specific.
Let's write this up. I recommend putting it in CommonJS/Scripts to
avoid the Transporter/AMD nomenclature that various people do not
like.  I think we should couch it in strong words about philosophy,
vote on it, and move on.


What do you mean by "strong words about philosophy"?

My assumption is that this format would become *the* format that people write their modules in if they've got browsers as their target audience. Node modules, for example, would not have a reason to change... but JS libraries that want to play nicely with the browser would actually check those two lines of scaffolding into their source control system.

Is that what it would say about when to use "Scripts" vs. "Modules"? I think I'm personally more in favor of a Modules/1.2 or 2.0 that gives specific guidance about when to add the define().

Kevin

Tim Schaub

unread,
Oct 20, 2010, 3:16:55 PM10/20/10
to comm...@googlegroups.com
On 10/20/10 1:14 PM, Kevin Dangoor wrote:
> On Wed, Oct 20, 2010 at 2:59 PM, Kris Kowal <kris....@cixar.com
> <mailto:kris....@cixar.com>> wrote:
>
> +1. I think that any other features should be implementation-specific.
> Let's write this up. I recommend putting it in CommonJS/Scripts to
> avoid the Transporter/AMD nomenclature that various people do not
> like. I think we should couch it in strong words about philosophy,
> vote on it, and move on.
>
>
> What do you mean by "strong words about philosophy"?
>
> My assumption is that this format would become *the* format that people
> write their modules in if they've got browsers as their target audience.
> Node modules, for example, would not have a reason to change... but JS
> libraries that want to play nicely with the browser would actually check
> those two lines of scaffolding into their source control system.
>
> Is that what it would say about when to use "Scripts" vs. "Modules"? I
> think I'm personally more in favor of a Modules/1.2 or 2.0 that gives
> specific guidance about when to add the define().
>

If you need to wrap your modules for use in a script tag...

Is there any other reason to use this wrapper (neglecting the SSJS
without server side dependencies suggestion)?

> Kevin
>
>
> --
> Kevin Dangoor
>
> work: http://mozilla.com/

> email: k...@blazingthings.com <mailto:k...@blazingthings.com>

Kris Zyp

unread,
Oct 20, 2010, 3:16:19 PM10/20/10
to comm...@googlegroups.com, Kris Kowal

What are we voting on? This is already in the spec. Is the vote/proposal
to rename AMD -> "Scripts"? I'd vote against that, as it is not very
descriptive, but not opposed to a rename. If you are looking for another
name, maybe "Module Instantiation" API?

--
Thanks,
Kris

Wes Garland

unread,
Oct 20, 2010, 3:21:30 PM10/20/10
to comm...@googlegroups.com

On Wed, Oct 20, 2010 at 2:59 PM, Kris Kowal <kris....@cixar.com> wrote:
+1.

-10000

This proposal requires CommonJS Environments to implement module scopes as functions.

Wes

--

Kris Kowal

unread,
Oct 20, 2010, 3:28:43 PM10/20/10
to comm...@googlegroups.com
On Wed, Oct 20, 2010 at 12:21 PM, Wes Garland <w...@page.ca> wrote:
> -10000

Sorry, I think you only get 1 point. Would you like to donate 9999
points to fight human trafficking instead?

> This proposal requires CommonJS Environments to implement module scopes as
> functions.

No, I think it should be clear that this specification does not impose
any requirements on existing CommonJS/Modules loaders. It is a
different format that exists to prevent the gap between our
communities from growing, and to provide a consistent compilation
target that the RequireJS community can use. The RequireJS community
is of course welcome to solicit the same format or a superset thereof
as a first class module format in which modules are written, but you
didn't hear it from me.

Kris Kowal

Rik Arends

unread,
Oct 20, 2010, 3:29:29 PM10/20/10
to comm...@googlegroups.com
Hi Guys,

Well i do suggest to try to get the requireJS guy on board on this or else not much will have been won.
If requireJS is adapted to use this style of define, a fully useable implementation for the browser will be there ready to use.
I did read a tweet that they just completed refactoring Dojo to the current requireJS module def, so it might take a bit of convincing.

Beyond this very basic form, i think also we need to clear up what consists as a 'package' or how search paths work.
because i believe requireJS uses lib/main.js, whereas commonJS uses index.js and some other slight differences.
It feels like if we can get these things to be the same much will be won for Javascript everywhere.
But it will require() some convincing on both sides now.

Best

Rik Arends

Kris Kowal

unread,
Oct 20, 2010, 3:36:11 PM10/20/10
to comm...@googlegroups.com
On Wed, Oct 20, 2010 at 12:29 PM, Rik Arends <r...@javeline.nl> wrote:
> Beyond this very basic form, i think also we need to clear up what consists as a 'package' or how search paths work.
> because i believe requireJS uses lib/main.js, whereas commonJS uses index.js and some other slight differences.
> It feels like if we can get these things to be the same much will be won for Javascript everywhere.
> But it will require() some convincing on both sides now.

main.js is a default for the Packages/Mappings specification.
index.js is an extension of Node/NPM for a "default" module for a
directory, similar to "__init__.py", and I personally don't support it
because it would mask a file in the parent directory or vice versa,
which is an unacceptable hazard, mitigated nicely by the
Mappings/main.js.

I think require, exports, and module are our common ground. Wrapping
in scripts is an acceptable compromise in some very specific
situations that hopefully go away in the next five years permitting us
to remove a line at the top and bottom of these files to bring them
into the new world instead of some other horrible machinations.

And I think James Burke, the RequireJS guy, has been instrumental in
this discussion.

Kris Kowal

Wes Garland

unread,
Oct 20, 2010, 3:54:04 PM10/20/10
to comm...@googlegroups.com
On Wed, Oct 20, 2010 at 3:28 PM, Kris Kowal <kris....@cixar.com> wrote:
On Wed, Oct 20, 2010 at 12:21 PM, Wes Garland <w...@page.ca> wrote:
> -10000

Sorry, I think you only get 1 point. Would you like to donate 9999
points to fight human trafficking instead?

You can do that?!  In that case, Yes! Absolutely!
 
> This proposal requires CommonJS Environments to implement module scopes as
> functions.

No, I think it should be clear that this specification does not impose
any requirements on existing CommonJS/Modules loaders.

I'm confused.

define() appears to accept a function argument, which is to act as a placeholder for the scope of the module which is about to be loaded, does it not?

It also appears to be put forth as another idiom in which to author CommonJS.

If both these statements are true, then I believe my conclusion is correct.

If either of them is false, then I am wrong.

Wes

Christoph Dorn

unread,
Oct 20, 2010, 6:46:34 PM10/20/10
to comm...@googlegroups.com
On 10-10-20 12:54 PM, Wes Garland wrote:
> It also appears to be put forth as another idiom in which to author
> CommonJS.

Right. That is the whole point.


> If both these statements are true, then I believe my conclusion is correct.
> If either of them is false, then I am wrong.

In my other post I stated that this format should be a strict feature
subset of Modules/1.1.1 and used if the author wants to target browsers
(as well as servers).

Can server-loaders not strip the top and bottom line from the source
before loading the module if present? That is what I was thinking.

It would require the "wrapping" to be strictly:

define(function(require, exports, module) {
...
});

*and* the modules authored in this way *must* function either way. If
they do not, they *fail* to meet the spec and should be authored as
Modules/1.1.1

Christoph

Christoph Dorn

unread,
Oct 20, 2010, 7:03:41 PM10/20/10
to comm...@googlegroups.com

I think what KrisK is getting at is to specify the above format as
CommonJS/Scripts and champion it as the format to use when *writing*
CommonJS modules for the browser (one module per file).

I personally would rename AMD to Modules/Transport/E and make it clear
it is to be used for transporting/packaging modules only, *not
authoring*. The consequence would be dropping the anonymous module
feature from the AMD spec as it would be achieved by CommonJS/Scripts. I
could be totally off on these changes?

We really need James' and other browser loader implementers feedback to
OK this approach as proper and useful otherwise it is of no consequence
as mentioned by Rik.

Christoph

Wes Garland

unread,
Oct 20, 2010, 7:14:23 PM10/20/10
to comm...@googlegroups.com
On 10-10-20 12:54 PM, Wes Garland wrote:
It also appears to be put forth as another idiom in which to author
CommonJS.

Right. That is the whole point.

Okay.  So let me understand with crystal clarity:

You are proposing the introduction of
  1. an alternate module format,
  2. which does not execute as-is on existing implementations,
  3. whose sole benefit is that it can be used to DIRECTLY author modules which can be included in script tags
and that this is required because the current module format requires a choice between either
  1. Using a build step
  2. Using a server-side process
  3. Using XHR
  4. Using an as-yet undiscovered or unexplored solution (such as SCRIPT tag injection into IFRAME, or loading JS via CANVAS)
For the record, when the CommonJS Module Format was specified, these limitations were well understood, and nobody said, "boo".  At the time, we were focused on developer-friendly idiom and securability. 

I also believe that there are infinite number of people who can stir the pot ad nauseum over non-issues, and that spending time on them has negative value.

Wes

James Burke

unread,
Oct 20, 2010, 7:34:42 PM10/20/10
to comm...@googlegroups.com
On Tue, Oct 19, 2010 at 9:07 AM, Christoph Dorn
<christ...@christophdorn.com> wrote:
> Base Format:
>
>  define(function(require, exports, module) {
>      var bar = require('bar'),
>      baz = require("baz");
>  });
>
>  Requires scraping for require()'s (already a requirement for 'lean'
> deployment of Modules/1.1)
>
>
> Extended Format:
>
>  define([
>    "bar",
>    "baz"
>  ],
>  function(require, exports, module) {
>      var bar = require('bar'),
>      baz = require("baz");
>  });

+1 for having that in some spec proposal, I do not care about the name
of that proposal.

If you want to leave out allowing of module ID in the define call for
when there are more than one module in a file (for optimized
transport), that does seem different than what Kris Zyp wrote in the
AMD proposal, but if the module ID is allowed, then it seems like a
rename of the what Kris Zyp wrote out, which is fine with me, just
pointing out how things relate.

End result, the above works in RequireJS today.

James

James Burke

unread,
Oct 20, 2010, 7:46:26 PM10/20/10
to comm...@googlegroups.com
On Wed, Oct 20, 2010 at 4:14 PM, Wes Garland <w...@page.ca> wrote:
> and that this is required because the current module format requires a
> choice between either
>
> Using a build step
> Using a server-side process
> Using XHR
> Using an as-yet undiscovered or unexplored solution (such as SCRIPT tag
> injection into IFRAME, or loading JS via CANVAS)
>
> For the record, when the CommonJS Module Format was specified, these
> limitations were well understood, and nobody said, "boo".  At the time, we
> were focused on developer-friendly idiom and securability.
>
> I also believe that there are infinite number of people who can stir the pot
> ad nauseum over non-issues, and that spending time on them has negative
> value.

I hope this is the last I will say about arguing for a script tag
friendly format, since I believe this is one of the soft issues that
just makes noise, but Wes seems to be curious about the motivation.

To Wes and probably others not seeing what the big deal is about
script tag execution, I believe this is one of those soft issues we
will not agree upon. I believe there was not as much gnashing of teeth
when the original module format was ratified because the participants
of the group at that time (started as ServerJS) were biased to not
seeing in script execution as an issue. Now that there are
browser-focused *implementors* with a history of module support (via
Dojo) I would expect the conversation to come up.

Both Dojo and YUI have gone with script tag execution. Dojo has done
this after years of using an XHR+eval loader, and we had options for a
"debugAtAllCosts" which did extraordinary tricks to make XHR-based
loading even more debuggable. We had an xdomain loader we used that
enabled CDN loading of modules via script tags, and it worked in
conjunction with the XHR loader.

We got it to work, but it is a noticeable developer tax, and it goes
away with script tag execution. Development is faster, there are less
things for the developer to worry about because there is less plumbing
involved and fewer edge cases. True, part of that was because Dojo
used *sync* XHR when *async* XHR was better, but the multiple
execution paths (xhr, xdomain scripts, debugAtAllCosts, all could be
used with each other) has been more of a tax than a syntax that works
with script tags.

End result, I suggest we stop talking about if it is a valid case or
if it can be mitigated by more tools and browser config changes. There
are enough browser developers that feel this is important that this
requirement will not go away, and it is based on real-world experience
using the tricks. We've been there, done that. I am aware of all the
tricks that have been proposed (Dojo has discussed them before, we
even use some of them), and they have been found to be deficient. IE
support is still an unfortunate reality for most browser developers,
so that limits the choices even more. Let's move on. I believe arguing
this point further will not result in a change of heart from either
side, just more noise.

James

Wes Garland

unread,
Oct 20, 2010, 9:40:53 PM10/20/10
to comm...@googlegroups.com
On Wed, Oct 20, 2010 at 7:46 PM, James Burke <jrb...@gmail.com> wrote:
To Wes and probably others not seeing what the big deal is about
script tag execution, I believe this is one of those soft issues we
will not agree upon.

It may very well be something that we simply have to agree to disagree on. These things do happen. :)

For the record I will clarify my position as succinctly as possible:
  1. I see value in script-tag loading; in fact that is my preferred way to load.
  2. I do not believe the benefit of authoring in script-tag format outweighs the cost of the proposed solution, when another adequate dev-platform solution exists (XHR) for those who are unable to have a build-step or server process
The chief reasoning behind #2 is that I do not believe that the primary deployment mechanics for non-trivial web sites will involve loading individual modules in individual, unprocessed scripts, and similarly, I think that trivial sites can be served adequately by XHR.

The module system I use locally delivers multiple modules at once in a single script tag, and yields good performance.  The modules are dynamically accumulated with a server-side process in the development environment, and accumulated/minimized with a build step when pushed to production.

Thus, my primary objection to the current proposal -- of a new module format which is directly editable in script-tag compatible code -- is that I see it as a breaking|fragmenting change with minimal technical benefits.

Both Dojo and YUI have gone with script tag execution. Dojo has done
this after years of using an XHR+eval loader, and we had options for a
"debugAtAllCosts" which did extraordinary tricks to make XHR-based
loading even more debuggable. We had an xdomain loader we used that
enabled CDN loading of modules via script tags, and it worked in
conjunction with the XHR loader.

These are (nearly) red herrings: all of these requirements can be met with a build step or server-side process.  The only time XHR is required is when the user cannot use a build step or a server-side process, in which case he falls back to XHR.... Which, by the way, works well in at least Firefox for me.
 
We got it to work, but it is a noticeable developer tax, and it goes
away with script tag execution. Development is faster, there are less
things for the developer to worry about because there is less plumbing
involved and fewer edge cases. True, part of that was because Dojo
used *sync* XHR when *async* XHR was better, but the multiple
execution paths (xhr, xdomain scripts, debugAtAllCosts, all could be
used with each other) has been more of a tax than a syntax that works
with script tags.

Now *this* is, at least to my me, a sound argument. To be clear - not enough to sway me, but sound.  It's possible that's it's been made before and been drowned out in the noise, but maybe at least this thread can serve as a community lesson.

The reason this discussion has been so hard is that it was started based on a misrepresentation of the truth ("require(X) does not work in the browser") which turned into a meme that very turned into an article of religious faith. This started more than a year ago BTW -- possibly before you were even on the list.

Next, Transports/C/Transports/D were presented as a fait-accompli and the only possible solutions to this lie.  Most of us had tuned out for the Transports/x discussions -- I tuned out because I believed the principals were coming up with a way to transport CommonJS modules to the browser, while resolving dependencies. I never in a million years would have guessed that result would be the proposal of a new module format for CommonJS.
 
End result, I suggest we stop talking about if it is a valid case

Sure.  Let's take (direct-editable + script-tag-loadable) modules off the table for a minute, and go back to the three points I identified as browser requirements in my long email the other day:
  • dereference the module memo
  • event-based module provider
  • resolve dependencies
I think we have 100% agreement that require(X) should remain the way to derefence the module memo.

The event-based module provider, I assume you want to be something like depend().  I'm not fussy on the name, but the basic form is dictated by the browser -- loadModule(module, callback) or loadModules([modules], callback).  While we haven't standardized this yet, I don't think there is a lot of room for discussion.

I also think dependency resolution is important, and in particular, I think depend() has gotten this wrong.  Dependencies should be identified by the component with the dependencies, not the user using the component.  That is, I think dependencies should be described by the callee, not the caller. Dependencies need to travel programmatically with the module, and the module user should not need to know what they are.

If CommonJS is going to specify another module format, I believe that the dependency issue should be solved, and that callee-described dependencies are hugely important.

The module.dependencies proposal I put forward earlier this week is incomplete and does not pass the CommonJS module test suite, however I am working on another solution which I'm confident will work.  This solution, however, requires reading a small amount of the module's text before executing it. This solution is also verifiable no risk of script-scraping parse errors.

Do you have any experience and/or insight to offer here?  Do you know of a module-oriented way to annotate dependencies which can be used effectively at run time? How does RequireJS solve the transitive test program problem?  (Can RequireJS run the test suite?)

Stefaan

unread,
Oct 21, 2010, 5:44:17 AM10/21/10
to CommonJS


On Oct 21, 2:40 am, Wes Garland <w...@page.ca> wrote:
> On Wed, Oct 20, 2010 at 7:46 PM, James Burke <jrbu...@gmail.com> wrote:
> ...
> I also think dependency resolution is important, and in particular, I think
> depend() has gotten this wrong.  Dependencies should be identified by the
> component with the dependencies, not the user using the component.  That is,
> I think dependencies should be described by the callee, not the caller.
> Dependencies need to travel programmatically with the module, and the module
> user should not need to know what they are.
> ...

what if the developer would package his code in a require.ensure to
declare the dependencies?

require.dependencies(['x'], function () {
var x = require('x');
});

and then that could be transported *without* scraping as:

define(function() {
require.dependencies(['x'], function () {
var x = require('x');
});
)};

or for optimized transport with scraping as:

define(['x'], function () {
var x = require('x');
});

or to avoid problems when developer's code is not completely
encapsulated, just leaving the original developer's
require.dependencies in the code:

define(['x', 'y'], function () {
// do some stuff
require.dependencies(['x'], function () {
var x = require('x');
});
// do some other stuff
require.dependencies(['y'], function () {
var x = require('y');
});
// do yet some other stuff
});

my point is that the method for a developer to declare his
dependencies is already there - this is essentially a require.ensure.
although with one semantical difference that require.dependencies can
be used for scraping by a transporter, while require.ensure perhaps
should not to allow for lazy and conditional dynamic loading - i.e.
only when needed:

if (myCondition) {
require.ensure(['x'], function () {
// do something with x
});
}
else {
require.ensure(['y'], function () {
// do something with y
});
}

Stefaan

Rik Arends

unread,
Oct 21, 2010, 6:47:05 AM10/21/10
to comm...@googlegroups.com
Sounds like a lot of unnecessary complexity to me, i think doing something very simple to
extend commonJS to do script-tag loading with dependencies should be the way forward right now.

I would really like to see rapid consensus on a format such as proposed, so we can all get on with writing modules.
We are refactoring our code 'right now' to requireJS, Dojo is doing the same 'right now' and we can hopefully still come to an agreement
This proposal will require us to find-replace the whole source base again to fit this format, and requireJS will need to be adapted.
Talk another month (or two) and i think the train will have left and field will have split.

The proposal that has been passed around looks like this:

define("compile name", ["dep",.. ], function(require, exports, module){
..normal commonJS module..
});

Both compile name and dep are optional. Compile name should only be inserted by a packaging tool.
In this the only real global is define, the others are passed into the function scope similarly to how nodeJS now implements it too.
When dependencies are not given they can be scraped using a callback.toString().match(). (with a warning in the browser console perhaps)
This means that modifying commonJS modules to this format really adds only a simple wrap, and then everybody is happy.

Another less important thing to consider are the requireJS plugins, where you can provide an alternate loading methods such as
var x = require('text!somefile.txt'); to require, which is very useful for non-js resources. It would be great if we can find a way to extend require that way in other environments too.

IMHO coming to ANY agreement on a common format outweighs any or all problems about what it looks like.
We should not let any pet peeves get in the way of such an important decision for Javascript as the future platform of software development.
Personally i find this proposal could be good for everyone and i would happily write modules this way.

Best

Rik Arends

Ajax.org/Cloud9IDE

Wes Garland

unread,
Oct 21, 2010, 8:50:49 AM10/21/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 6:47 AM, Rik Arends <r...@javeline.nl> wrote:
Sounds like a lot of unnecessary complexity to me, i think doing something very simple to
extend commonJS to do script-tag loading with dependencies should be the way forward right now.

You do understand, right, that making the proposed module-authoring format change causes modules written in the future to NOT WORK on current CommonJS environments?
 
Your characterization that I am arguing about a pet peeve is disingenuous, and frankly insulting. I am making sure that CommonJS does not make breaking changes without a very good reason.

And you, Rik, in particular, need to police your thoughts. Every single message you have posted on this topic has built arguments on top of lies.  CommonJS *can* load from a script tag. What they *can't* do is load from a script tag without either a build step, or a server-side process.

I would really like to see rapid consensus on a format such as proposed, so we can all get on with writing modules.

Rapid consensus is less necessary than a thorough exploration of the issues.  The issue-space has changed *dramatically* in the last week from "OMG CommonJS does not work on the browser" (lie) and "CommonJS modules cannot load in a script tag without an extra step".
 
We are refactoring our code 'right now' to requireJS, Dojo is doing the same 'right now' and we can hopefully still come to an agreement 
This proposal will require us to find-replace the whole source base again to fit this format, and requireJS will need to be adapted.
 
Oh, give me a break.

Write your code in the current CJS-MF and use a build step to deploy while this is being sorted out.  I could write a 20-line shell script in under an hour to do this. Or use XHR to load. Or write your modules in the new format with regular formatting or annotation so that  you can sed them later.

When dependencies are not given they can be scraped using a callback.toString().match(). (with a warning in the browser console perhaps)

Except on platforms which do not have a decompiler (function.prototype.toSource() is not part of ECMAscript). There is at least one embedded platform that does not.
 
This means that modifying commonJS modules to this format really adds only a simple wrap, and then everybody is happy.

Except for the people who download an updated library which has been updated to Modules/2.0, and they are using a CommonJS Environment built on Modules/1.1.  Then their code throws an exception instead of running.
 
Another less important thing to consider are the requireJS plugins, where you can provide an alternate loading methods such as
var x = require('text!somefile.txt'); to require, which is very useful for non-js resources. It would be great if we can find a way to extend require that way in other environments too.

We had a proposal for this on the books over a year ago. module.resource(), IIRC.  I think overloading require(X) is a loser, although require.resource() would work for me.
 
IMHO coming to ANY agreement on a common format outweighs any or all problems about what it looks like.

Keeping CommonJS stable is hugely important for some of us. And we already had an agreement.

Wes

khs4473

unread,
Oct 21, 2010, 8:59:08 AM10/21/10
to CommonJS
Wes, would you mind commenting on my recent post in the other thread,
from a GPSEE point of view? And here, let me get you some
coffee. ; )

Wes Garland

unread,
Oct 21, 2010, 9:09:08 AM10/21/10
to comm...@googlegroups.com
>  And here, let me get you some coffee.  ; )

How did you know my cup was empty... Is my web cam on?!

Stefaan

unread,
Oct 21, 2010, 9:10:22 AM10/21/10
to CommonJS
very interested in this - can somebody give me a pointer where I could
find some info on this module./require.resource?

Stefaan

Wes Garland

unread,
Oct 21, 2010, 9:40:02 AM10/21/10
to comm...@googlegroups.com

very interested in this - can somebody give me a pointer where I could
find some info on this module./require.resource?

Wes Garland

unread,
Oct 21, 2010, 9:51:01 AM10/21/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 5:44 AM, Stefaan <stefaan.c...@advalvas.be> wrote:
what if the developer would package his code in a require.ensure to
declare the dependencies?

require.dependencies(['x'], function () {
 var x = require('x');
});

You know, if somebody put this forth as a module-authoring format that expresses dependencies in the callee's context as part of Modules/2.0 or whatever -- along with a sound argument as to why this was the best way -- I might bite:

/** Area module */
require.depend(['math'], function()
{

  exports.rectangle = function (a, b)
  {
    require('math').multiply(a,b);
  };

}

Wes
 

khs4473

unread,
Oct 21, 2010, 9:58:56 AM10/21/10
to CommonJS
require, exports, and module have to be arguments to the factory
function, for it to work on RequireJS (because the code is executed in
the global scope):

require.depend(['math'], function(require, exports, module)
{
exports.rectangle = function (a, b)
{
require('math').multiply(a,b);
};
}

On Oct 21, 9:51 am, Wes Garland <w...@page.ca> wrote:

Stefaan

unread,
Oct 21, 2010, 10:00:43 AM10/21/10
to CommonJS


On Oct 21, 2:51 pm, Wes Garland <w...@page.ca> wrote:
> On Thu, Oct 21, 2010 at 5:44 AM, Stefaan <stefaan.coussem...@advalvas.be>wrote:
>
> ...
> along with a sound argument as to why this was the best way
> ...

you sure you already drank your coffee :-)

sound arguments - sure, I think it was shown in my post that this
doesn't cost anything extra, it's already proven to work in some
'require.ensure' implementations.
the best way - no way to be sure about this one, I guess

Wes Garland

unread,
Oct 21, 2010, 10:03:58 AM10/21/10
to comm...@googlegroups.com
> require, exports, and module have to be arguments to the factory function,

Good points. I also forgot the return keyword in exports.rectangle. :)

khs4473

unread,
Oct 21, 2010, 10:11:59 AM10/21/10
to CommonJS
As I stated on the other thread, I would want the dependency array
(['math'] in this case) to be informational only. In other words,
inclusion in the dependency array does not guarantee that that that
module is loaded or initialized when the factory executes. The
require calls should be the only truth when it comes a module's
dependencies.

In my loader, I wouldn't need the dependency array, so I would ignore
it.

Christoph Dorn

unread,
Oct 21, 2010, 12:38:52 PM10/21/10
to comm...@googlegroups.com
I think all the relevant issues have been discussed in various parallel
threads. Since I started this thread I thought I would put out a
revision to the original proposal. The goal is to nail down the changes
we need to make. We can then revise/write the specs and vote.

I think these discussions have been valuable and are a sign that the
CommonJS group does not want to treat browser implementer concerns as
second class. The browser environment is complex and necessitates some
concessions at least for now (I know this is a point of contention but I
think it has been sufficiently argued). This is a fact that must be
recognized.

CommonJS/Scripts/1.0 ~

module.define(["bar", "baz"], function(require, exports, module) {


var bar = require('bar'),
baz = require("baz");
});

* An alternative module source format for better browser support
* The first argument is optional and for informational purposes only (to
avoid require() scraping if desired and supported by loader)
* module.define is used to keep the dependency declaration with the module
* module.define can be used to test if the CommonJS/Scripts format is
used as opposed to CommonJS/Modules
* One module per file
* Module ID is derived from filename
* Module must function with the wrapper stripped yielding a
CommonJS/Modules module

CommonJS/Modules/2.0 ~

* Version is bumped to indicate that loader supports CommonJS/Scripts/1.0
* Loader checks for module.define to identify CommonJS/Scripts module
* Loader may strip CommonJS/Scripts wrapper before compiling source

CommonJS/Transport/E ~

define("moduleId", ["bar", "baz"], function(require, exports, module) {


var bar = require('bar'),
baz = require("baz");
});

* All arguments are required
* define is a free variable
* Never used for module authoring directly; only for transport
* Supports multiple modules per file

Is this getting closer to a solution?

Christoph

On 10-10-19 9:07 AM, Christoph Dorn wrote:
> Goal:
>
> A module source format that works natively on the server and browser
> *and supports necessary browser loading intricacies*.


>
>
> Base Format:
>
> define(function(require, exports, module) {
> var bar = require('bar'),
> baz = require("baz");
> });
>
> Requires scraping for require()'s (already a requirement for 'lean'
> deployment of Modules/1.1)
>
>
> Extended Format:
>
> define([
> "bar",
> "baz"
> ],
> function(require, exports, module) {
> var bar = require('bar'),
> baz = require("baz");
> });
>

> Used for more complex modules where scraping is error prone.
>
> This assumes one module per source file. Let's leave the async and
> multi-module transport aspects out of this discussion. They can be
> addresses subsequently.
>
> I believe this addresses all the core issues at hand.
>

> Please keep arguments specific and do now throw blankets. Let's flush
> out the pros and cons of this format or slight derivatives thereof.
>
> Christoph
>

jbrantly

unread,
Oct 21, 2010, 12:47:39 PM10/21/10
to CommonJS
On Oct 21, 9:38 am, Christoph Dorn <christoph...@christophdorn.com>
wrote:
> Is this getting closer to a solution?

Yes! Couldn't have said it better myself. I'm hoping we can get some
movement on both sides towards some middle ground like this.

+1

khs4473

unread,
Oct 21, 2010, 12:47:45 PM10/21/10
to CommonJS
Looks good to me. Can we leave out Transport/E or is that something
we have to deal with now?


On Oct 21, 12:38 pm, Christoph Dorn <christoph...@christophdorn.com>
wrote:

Rik Arends

unread,
Oct 21, 2010, 12:59:03 PM10/21/10
to comm...@googlegroups.com
Sounds like a lot of unnecessary complexity to me, i think doing something very simple to
extend commonJS to do script-tag loading with dependencies should be the way forward right now.

You do understand, right, that making the proposed module-authoring format change causes modules written in the future to NOT WORK on current CommonJS environments?

Yes it will require some changes to the commonJS module loaders, just as it will to requireJS.
But both things are highly doable. We are still before the wave of massive adoption so its either now or never.
Again, thats why i feel time pressure. I really do not want to end up in a case where i have to go and preprocess modules and worry about it.
I am forced to worry about it right now in our node vs browser code. The business of most people here is making JS easy to use for devs and this 'grab and use' of a module is an essential part of it.

 Your characterization that I am arguing about a pet peeve is disingenuous, and frankly insulting. I am making sure that CommonJS does not make breaking changes without a very good reason.

I am happy you take this task so seriously, and i can see there is a lot of thought on issues i had not even remotely considered.
However i wanted to emphasize that the goal here should be bigger than any particular dislikes.
.
And you, Rik, in particular, need to police your thoughts. Every single message you have posted on this topic has built arguments on top of lies.  CommonJS *can* load from a script tag. What they *can't* do is load from a script tag without either a build step, or a server-side process.

I realize this is a sensitive issue, but i will keep pressing this as somehow the real meaning of it has trouble getting through.
Watering every statement down with 'well yes you COULD do it if you XYZ' defeats this point. XYZ is not a solution the frontend guys 
can live with, its been tried, dismissed and explained and now off the table for us so i do not keep referring to it. 

I would really like to see rapid consensus on a format such as proposed, so we can all get on with writing modules.
Rapid consensus is less necessary than a thorough exploration of the issues.  The issue-space has changed *dramatically* in the last week from "OMG CommonJS does not work on the browser" (lie) and "CommonJS modules cannot load in a script tag without an extra step".

I do think that thoroughly looking at it is good, however i also think there is real time pressure to align the basics.

 
We are refactoring our code 'right now' to requireJS, Dojo is doing the same 'right now' and we can hopefully still come to an agreement 
This proposal will require us to find-replace the whole source base again to fit this format, and requireJS will need to be adapted.
 
Oh, give me a break.
Write your code in the current CJS-MF and use a build step to deploy while this is being sorted out.  I could write a 20-line shell script in under an hour to do this. Or use XHR to load. Or write your modules in the new format with regular formatting or annotation so that  you can sed them later.

I guess you do not share my feeling of urgency in aligning major piles of frontend JS code that are being modified right now to fit requireJS to be actual commonJS modules. Some companies are even working on embedding nodeJS into phones making the commonJS part perhaps even near immutable soon. We can indeed easily find-replace whatever we make, but the longer 2 real competing module formats are used in the wild the more it will hurt to change it. And i have the feeling that the break-off point is right about now.

When dependencies are not given they can be scraped using a callback.toString().match(). (with a warning in the browser console perhaps)

Except on platforms which do not have a decompiler (function.prototype.toSource() is not part of ECMAscript). There is at least one embedded platform that does not.

Yes which is partially why i dislike scraping, but making the dependencies 'optional' is a concession to easily fit with commonJS. Which is not a bad starting point. Also that environment should not even need to scrape at all because require() can just keep on working the same way it did before.

This means that modifying commonJS modules to this format really adds only a simple wrap, and then everybody is happy.

Except for the people who download an updated library which has been updated to Modules/2.0, and they are using a CommonJS Environment built on Modules/1.1.  Then their code throws an exception instead of running.

Yes there have to be changes on both sides, but it can still be done.

 
Another less important thing to consider are the requireJS plugins, where you can provide an alternate loading methods such as
var x = require('text!somefile.txt'); to require, which is very useful for non-js resources. It would be great if we can find a way to extend require that way in other environments too.

We had a proposal for this on the books over a year ago. module.resource(), IIRC.  I think overloading require(X) is a loser, although require.resource() would work for me.

Yeah that could be fine too, although i do not think its important enough right now to warrant arguing.

 
IMHO coming to ANY agreement on a common format outweighs any or all problems about what it looks like.

Keeping CommonJS stable is hugely important for some of us. And we already had an agreement.

I understand, but i also think commonJS worked in fair isolation from a lot of frontend groups in the past, 
which is perhaps also the reason why our voice has not been loud enough in the previous agreement.

Wes

--
Wesley W. Garland
Director, Product Development
PageMail, Inc.
+1 613 542 2787 x 102

Christoph Dorn

unread,
Oct 21, 2010, 1:03:14 PM10/21/10
to comm...@googlegroups.com
On 10-10-21 9:47 AM, khs4473 wrote:
> Looks good to me. Can we leave out Transport/E or is that something
> we have to deal with now?

We can leave it out, but... I included it as AMD seems to combine
Transport C and D and started this whole debate and I wanted to make the
distinction between module.define() and define().

If the AMD people can agree on the split I propose we move forward with
all three (keep in mind Transport/E would just be a leading proposal -
not a voted on spec).

Christoph

Wes Garland

unread,
Oct 21, 2010, 1:09:23 PM10/21/10
to comm...@googlegroups.com
Chris;

I'm sorry, I don't understand your proposal. Are you advocating three different ways to write modules? Or were you advocating for one of those solutions?

I have enormous reservations about any proposal that requires that the CommonJS Environment defer securability to the loaded module.

Wes



Christoph

--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.

Rik Arends

unread,
Oct 21, 2010, 1:10:41 PM10/21/10
to comm...@googlegroups.com
This looks like a workable solution.
Putting define on module makes it easier to check if it is there, if you would need to do so.

How would you propose to do define when the module is packaged?
I would suggest making this a separate function, so people cannot abuse define with an ID.

module.packed("moduleID", ["deps"], function(require,exports,module){})

Other than that +1, format looks fine.

Rik

khs4473

unread,
Oct 21, 2010, 1:18:52 PM10/21/10
to CommonJS
When it's packaged, it would be in something like Transport/E (from
Christoph's post above), which is exactly like your example, except
that for transport it shouldn't be hung off of "module".

Christoph Dorn

unread,
Oct 21, 2010, 1:22:28 PM10/21/10
to comm...@googlegroups.com
On 10-10-21 10:10 AM, Rik Arends wrote:
> This looks like a workable solution.
> Putting define on module makes it easier to check if it is there, if you would need to do so.
>
> How would you propose to do define when the module is packaged?
> I would suggest making this a separate function, so people cannot abuse define with an ID.

Hence module.define() and define().

CommonJS/Transport/E ~

define("moduleId", ["bar", "baz"], function(require, exports, module) {
var bar = require('bar'),
baz = require("baz");
});

or

define("moduleId", function(module) {


module.define(["bar", "baz"], function(require, exports, module) {
var bar = require('bar'),
baz = require("baz");
});

});

Christoph

Christoph Dorn

unread,
Oct 21, 2010, 1:36:46 PM10/21/10
to comm...@googlegroups.com
On 10-10-21 10:09 AM, Wes Garland wrote:
> Chris;

Who is Chris? ;)


> I'm sorry, I don't understand your proposal. Are you advocating three
> different ways to write modules? Or were you advocating for one of those
> solutions?

One pure format (CommonJS/Modules) and one wrapped format
(CommonJS/Scripts) that can be converted to CommonJS/Modules.


> I have enormous reservations about any proposal that requires that the
> CommonJS Environment defer securability to the loaded module.

Can you explain the problem based on this:

module.define(["bar", "baz"], function(require, exports, module) {
var bar = require('bar'),
baz = require("baz");
});

My assumption was that the loader, after parsing and executing the
module, can look for module.define and treat it the same as:

define(["bar", "baz"], function(require, exports, module) {
var bar = require('bar'),
baz = require("baz");
});

which seems to not exhibit the securability problem?

If "module" is the wrong variable let's use a different one. The reason
I used module is because it makes intuitive sense and keeps the
dependency array with the module?

Can you explain the exact downsides of defining modules with:

module.define(["bar", "baz"], function(require, exports, module) {
var bar = require('bar'),
baz = require("baz");
});

and can we live with these downsides as limitations of the
CommonJS/Scripts format? If a module cannot be coded with these
limitations the author must use CommonJS/Modules.

Christoph


Wes Garland

unread,
Oct 21, 2010, 2:47:56 PM10/21/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 1:36 PM, Christoph Dorn <christ...@christophdorn.com> wrote:
Who is Chris? ;)

Wait, isn't that the default name for people on this mailing list? Can you explain the problem based on this:
module.define(["bar", "baz"], function(require, exports, module) {
   var bar = require('bar'),
       baz = require("baz");
});

Off the top of my head, I have one problem with this proposal as an authoring format: It does not run on Module/1.1 systems    (so should be reserved for Modules/2.0 or whatever)

Well, that and it's ugly, but sometimes we have to live with ugly. ;)

Incidentally, I would prefer to call it module.declare.  Because that's exactly what it does

/**
 *  Declare a new module
 *  @param   dependencies    An array of String listing dependencies, as they
 *                           are resolved by require() in this module

 *  @param   theModule       A function which provides the module. Wrapping a
 *                           Modules/1.1 modules in function() { require, exports, module }

 *                           will yield the same behaviour as the module previously did in
 *                           a CommonJS Modules/1.1 environment.
 *  @note    This routine may only be called once per file.

 */
module.declare = function (dependencies, theModule) {};

/**
 *  Wrapper for a CommonJS Module/2.0 Module. The contained function is a proper
 *  superset of a Modules/1.1 module.

 *  @param   require   A function which dereferences the environment's module memo,
 *                     dependent on the name of this module. This is a unique instance
 *                     of require
which can be passed as an argument to other modules,
 *                     sharing it's authority.

 *  @param    exports  An empty object which is to be decorated with this module's
 *                     public properties

 *  @param module      A unique instance of a ModuleObject, whose id property lists a
 *                     canonical reference to this module

 */
theModule = function (require, exports, module) {};

This gives us modules which look like this:

/** @file sidelen.js    Module for calculating the lengths of the sides of various shapes
 *  @version 1.0
 */

module.declare( ["arithmetic", "transidentals"], function(require, exports, module)
{
  exports.square = function square(l)
  {
    return require("math").add(l, l, 1, 1);
  };

  exports.circle = function circle(r)
  {
    var d = require("math").add(r, r);
    return require("math").multiply(d, require("transcedentals").PI);
  }
});

My assumption was that the loader, after parsing and executing the module, can look for module.define and treat it the same as:

define(["bar", "baz"], function(require, exports, module) {
   var bar = require('bar'),
       baz = require("baz");
});

which seems to not exhibit the securability problem?

I don't really see how this is different from the above, except for the namespace pollution.  The securability problem arises when you have modules specifying their own identity.

Just like in a club. If you ask patrons for their driver's license, they can give you a false one.  But if you kidnap them at birth and keep them until they are old enough to drink, you can be sure they are of age.

Wes

Dean Landolt

unread,
Oct 21, 2010, 3:30:23 PM10/21/10
to comm...@googlegroups.com
Christoph...

Can you draw some brighter lines around the distinction between CommonJS/Modules/1.1, CommonJS/Scripts, and CommonJS/Transports/E? Can you explain what the difference is between CommonJS/Scripts and a Module format?

Stefaan

unread,
Oct 21, 2010, 3:37:10 PM10/21/10
to CommonJS
From the various threads I have been trying to follow the last days, I
think everybody is more or less in agreement here, except for the
exact scoping, namespacing and naming (so I'm going to give it yet
another name :-p):

We need something for *transport* that may include a module-ID or not
(aka. 'define',... ):

-> 'require.load("x", ["a","b"], function (require, exports, module)
{...});

We need something for *authoring without executing* that may include a
module-ID or not (aka. AMD-style authoring):

-> 'require.define("y", ["c", "d"], function (require, exports,
module) {...})

We need something that can run from a script-tag, i.e. *authoring and
executing* without needing to scrape for dependencies and that
shouldn't have a module-ID (aka. 'module.define', 'require.depend',
'loadModule',...):

-> 'require.run(["e", "f"], function (require, exports, module) {...})

All with explicit 'require', 'exports' and 'module' injects in the
factory-function to keep compatibility with existing Modules/*

Did I understand this wrong?

Stefaan

On Oct 21, 7:47 pm, Wes Garland <w...@page.ca> wrote:
> On Thu, Oct 21, 2010 at 1:36 PM, Christoph Dorn <
>

Stefaan

unread,
Oct 21, 2010, 3:46:57 PM10/21/10
to CommonJS
And I also can't wait for replies :-)

on the security aspects, something along the lines of:

'require.load'
with top-level ID: match with filename
with relative ID: make relative to filename
with no ID: take it from the filename

'require.define'
with top-level ID: check that it doesn't overwrite a module that is
not allowed to be overwritten
with relative ID: make relative to the module where it is defined, if
global scope then use some predefined root
with no ID: not allowed because one wouldn't be able to reference it

'require.run'
only allowed without ID

Stefaan
> > +1 613 542 2787 x 102- Hide quoted text -
>
> - Show quoted text -

jbrantly

unread,
Oct 21, 2010, 3:48:17 PM10/21/10
to CommonJS
I think it's a bit more complex than that. Wes has convinced me that
what's needed really is a brand new module specification. I do think,
however, that we're hovering around a viable solution to this whole
mess and it follows quite closely with cdorn's proposal. There's a
pretty good discussion here: http://chat.commonjs.org/mochabot/2010-10-21

James Burke

unread,
Oct 21, 2010, 4:21:34 PM10/21/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 9:38 AM, Christoph Dorn
<christ...@christophdorn.com> wrote:
> CommonJS/Scripts/1.0 ~
>
> module.define(["bar", "baz"], function(require, exports, module) {
>    var bar = require('bar'),
>        baz = require("baz");
> });
>

One of the goals for this format is to allow easy hand-coding, so I
prefer that only this form does not use "module.define" but just
"define". Also, since this form is closely aligned with the transport
format (just misses an ID), it is hard for me to see the need for an
extra global (at least in the browser) for this form.

If the concern is breaking out things that can or cannot have an ID, I
think it is fine to just stipulate that envs that do not allow named
modules properly throw if the first arg is a string. Presumably they
are doing argument validation anyway. Although it also seems possible
for those envs to allow named modules but throw if the name does not
match its expected value. For instance, if it was fed a set of modules
that were in a format that was used for a transport.

I also have a comment on injection vs availability, more below.

> CommonJS/Transport/E ~
>
> define("moduleId", ["bar", "baz"], function(require, exports, module) {
>    var bar = require('bar'),
>        baz = require("baz");
> });

I sent my +1 earlier, but immediately wanted to respond back, but had
to catch a plane. I need to amend the +1:

This gets to one of the issues that has been mentioned in the
discussions already, but I have not directly addressed before:
injection vs availability. In other words, executing the dependency to
allow for injection into the definition function (injection), or just
making sure the dependency is available for the first sync require("")
call, then when that require("") sync call happend, calling the
function definition (availability). Sorry if there are more standard,
official names for those two things.

What Kris Zyp has in the AMD proposal is injection and that is what
RequireJS supports now. So, the dependencies match up with function
arguments

define("moduleId", ["require", "exports", "module", "bar", "baz"],
function(require, exports, module, bar, baz) {
//Can still use require to fetch already-loaded dependencies in here
//if you do not like listing dependencies as function
//args. Best to just use the simplifed define with just a
//function in that case though and leave this form
//for code that is transformed for transport.


var bar = require('bar'),
baz = require("baz");
});

And "require", "exports" and "module" as module IDs mapped to the
CommonJS variables.

I still prefer this approach, which is different than what Christoph
suggested. I still prefer the injection approach because feels more
like what happens in a regular browser environment (scripts executed
in a particular order, not half-execute, then give another script a
chance to change things, then finish executing. It also fits
marginally better with allowing a module to export a function as the
exported value, in that there are fewer chances for surprises.

While availability gives you slightly more leeway in a circular
dependency case, those circular dependency cases are still very
fragile. If someone moves code around in one of the files, it will
likely break things. In other words, I do not believe that marginal
benefit to the circular case is worth giving up the benefits of
injection.

So I suppose I am still coming back to liking what was in AMD already,
but strengthening the language around the module ID as only being
there for transport, and it may be rejected for for security concerns,
and be very vocal about not encouraging people to hand code with a
module ID. I also think there should be examples in the AMD spec that
encourage the simple form for normal authoring:

define(function(require, exports, module) {
//traditional commonjs stuff in here.
});

as I believe this will be the most common form for folks that want a
simple upgrade path for existing traditional CommonJS modules.

James

jbrantly

unread,
Oct 21, 2010, 4:54:32 PM10/21/10
to CommonJS
On Oct 21, 1:21 pm, James Burke <jrbu...@gmail.com> wrote:
> So I suppose I am still coming back to liking what was in AMD already,
> but strengthening the language around the module ID as only being
> there for transport, and it may be rejected for for security concerns,
> and be very vocal about not encouraging people to hand code with a
> module ID. I also think there should be examples in the AMD spec that
> encourage the simple form for normal authoring:
>
> define(function(require, exports, module) {
>     //traditional commonjs stuff in here.
>
> });

+1 in general

I'm in support of creating a baseline that is just good enough to work
in the browser, and then everything else (id, injects, return exports)
is optional (or at least up for discussion) for the implementation
itself. And for a module to be the most portable, use only the
baseline.

We had some discussion in IRC as to whether or not everything beyond
the baseline should be in the spec and tagged "implementation
optional" or as additional extension specifications.

I understand your strong desire to use fun stuff like injects and
return exports, but in the spirit of cooperation, since those things
(I don't believe) have been totally agreed upon, can we set them aside
or at least make them less important than the larger goal of getting
an authoring module format that's loadable via <script>?

khs4473

unread,
Oct 21, 2010, 4:58:43 PM10/21/10
to CommonJS
- No IDs
- No injection
- One definition per file
- module.define or module.declare

or I'm out. My system runs just fine with Modules as they are. I
think it's time to ask yourself how much you want RequireJS to be
CommonJS complaint.

(And fwiw, AMD has received no vote by the CommonJS community.)


On Oct 21, 4:21 pm, James Burke <jrbu...@gmail.com> wrote:
> On Thu, Oct 21, 2010 at 9:38 AM, Christoph Dorn
>

Dean Landolt

unread,
Oct 21, 2010, 5:16:19 PM10/21/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 4:58 PM, khs4473 <khs...@gmail.com> wrote:
- No IDs
- No injection
- One definition per file
- module.define or module.declare

or I'm out.  My system runs just fine with Modules as they are.  I
think it's time to ask yourself how much you want RequireJS to be
CommonJS complaint.

(And fwiw, AMD has received no vote by the CommonJS community.)


IIUC AMD is RequireJS, at least for the purposes of this discussion. I do think it's received strong support -- as a transport format -- isn't this what Christoph recommended as Transport/E?

The problem comes down to whether it should be endorsed as a module authoring format. More coming on that -- I'm putting together an email summarize the points made by Wes and James Brantly on IRC but the long and short of it is yes, there is good reason to support some subset of AMD -- something like what Christoph suggested as ScriptModules -- something that falls right inside your requirements (no IDs, no injection, one declaration per file, module.declare (since it would have a different signature from the global AMD define it probably shouldn't be `define`).

Christoph Dorn

unread,
Oct 21, 2010, 5:18:34 PM10/21/10
to comm...@googlegroups.com

(I have not been monitoring irc)

Given we all agree on Wes' proposal of (+1 from me):

module.declare(["bar"], function (require, exports, module) {
var bar = require("bar");
exports.foo = function();
});

(with the dependency array being optional)

as an *alternate source format* for Modules/2.0 with the following as
the default:

var bar = require("bar");
exports.foo = function();

any *transport* format must *follow*. To me this means that a tarnsport
format:

* *May never be used for authoring modules directly*
* May insert a module ID
* May automatically transform the original source format *in any way*
to make it consumable by a specialized loader
* May contain other features for the purpose of using the same
transport format for not only transporting CommonJS modules

If you can automatically convert from:

module.declare(["bar"], function (require, exports, module) {
var bar = require("bar");
exports.foo = function();
});

to (transport format):

define("<ID>", ["require", "exports", "bar"], function (require,
exports, bar) {
exports.foo = function();
});

Then by all means. If this conversion is not possible then it is not a
CommonJS transport format.

I don't think we should vote on any transport formats for a while but
let them evolve and let loaders standardize since any loader can easily
support multiple formats (provided they an be distinguished).

I do think we need to vote on an alternative source format that can be
transformed into an acceptable transport format.

Is your preference for:

define("<ID>", ["require", "exports", "bar"], function (require,
exports, bar) {
exports.foo = function();
});

purely from a visual/mental/complexity perspective or are there real
technical concerns. If there are no technical concerns I think we have
found an alternative module format for Modules/2.0:

module.declare(["bar"], function (require, exports, module) {
var bar = require("bar");
exports.foo = function();
});

Christoph

jbrantly

unread,
Oct 21, 2010, 5:27:36 PM10/21/10
to CommonJS
On Oct 21, 2:18 pm, Christoph Dorn <christoph...@christophdorn.com>
wrote:
> purely from a visual/mental/complexity perspective or are there real
> technical concerns. If there are no technical concerns I think we have
> found an alternative module format for Modules/2.0:
>
> module.declare(["bar"], function (require, exports, module) {
>      var bar = require("bar");
>      exports.foo = function();
>
> });

+1

I think there's plenty of room for discussions on possible extensions
(injects, etc) but can we go ahead and start moving forward without
them?

Dean Landolt

unread,
Oct 21, 2010, 5:29:39 PM10/21/10
to comm...@googlegroups.com
I don't think we ever really need to vote on transport formats, right? The market can decide this.

 

I do think we need to vote on an alternative source format that can be transformed into an acceptable transport format.


I think it's a little bigger than this. If we're going to endorse and alternate format the state of affairs is completely unchanged -- we now have two competing, non-interoperable module formats.

Which one do you author in? No heuristics can really answer that question (especially as browsers gain features).

Is it a CommonJS/Module format? What's a ModuleScript, anyway? A module, by any other name, is still a module. So if that's our future, it looks just like the present -- same as it ever was...

If we're talking about an authoring format we're talking about Modules/2.0 -- I tried to right that point but I'm convinced there's really no way around it.

So if we're really talking about Modules/2.0, let's talk about Modules/2.0. It doesn't have to happen today, or even next month -- it can be a long, protracted conversation. Actually Wes threw out a few interesting ideas that could help us get 2.0 to be potentially more forward-compatible (or at least more flexible to shimming in future changes). But just creating another module format (why not five?) doesn't solve the fragmentation problem. It only serves to make it worse.

 

Stefaan

unread,
Oct 21, 2010, 5:39:13 PM10/21/10
to CommonJS
On Oct 21, 8:48 pm, jbrantly <jbran...@sent.com> wrote:
> I think it's a bit more complex than that. Wes has convinced me that
> what's needed really is a brand new module specification. I do think,
> however, that we're hovering around a viable solution to this whole
> mess and it follows quite closely with cdorn's proposal. There's a
> pretty good discussion here:http://chat.commonjs.org/mochabot/2010-10-21
>

I really think the situation is not that bad and that most of the
bridges to come to an agreement are already in place.
OK, after reading through this mochabot - still going on but my take
on some of the arguments up to now, in an attempt to create some
bridges:

*** Two Modules specs: I definitely do agree there should be no 2
different module formats, if this is absolutely required then that
would indeed have to be a Modules/2.0.
I can see 4 arguments being used to say that what is happening here
creates 2 different module formats:

1) authoring packaged code: if a wrapper can be easily stripped and
added again by a tool without adverse effect (except that the tool
hopefully will make less errors), then this is a non-issue IMO.

2) AMD injects in the factory function: although very nice indeed,
definitely a break with Modules/1* and would need a Modules/2* - but
for Modules/1* you could still use some wrok-around: push things like
the results from plugins onto a 'module.plugins' array instead of
injecting in the factory-function, but just don't do it for the real
module-IDs.

3) AMD allows to return exports: indeed a break with Modules/1 but I
would imagine it can be made harmless in most systems

4) AMD allows to return exports that are not a plain {} object,
definitely a break with Modules/1* and would need Modules/2* - I don't
think there is a workaround possible for this, other than attaching it
as a property to exports.

So in the end, IMO, 2) and 4) are the only problems that need to be
dropped if sticking to Modules/1*, and they both have a work-around
that is 100% comptible (be it not optimal or looking as nice) to
Modules/1*

*** No build-step to deploy:
I honestly don't see why this would be an absolute requirement. If
somebody can load a 'script' on a server, then why wouldn't it be
possible to package the script and load the 'packaged script' on the
server?

*** Fragmentation browser <-> server
This is in my opinion a no-no and is not really needed AFAICT,
provided we can come to an agreement that items 2) and 4) higher
cannot be supported as currently defined in AMD.

*** Packaging multiple modules in one file
This is still possible - I think the module-ID rules I wrote up higher
would solve that

*** Unifying transport/authoring/script-tags
I believe they are all 3 very much related but have semantics (esp
around security) that are different enough to warrant a separation.
But in the end, if people feel really really strong about this, then I
could live with unifying, provided there are solutions for the
security issue that don't create extra limitations.

*** moving declaration of dependencies to the module-author
Completely agree that there is a need for that (esp. when running from
script-tags). This is essentially already availablein some form and
working on some platforms: 'require.ensure' - I would propose an
additional 'require.run' (or 'require.depend' or 'module.declare')
which is from a coding perspective identical to 'require.ensure' - *it
can be an alias* - but to be able to keep a separate 'require.ensure'
for *conditional* dynamic loading (which is BTW not really possible
when tools scrape for 'require'd module-IDs). Also, this wrapper can
be dropped for modules that don't have any dependencies. Finally,
just as 'require.ensure', this wrapper is essentially part of the code
- not a transport- or authoring-wrapper or packaging-wrapper.

*** exports-promises
Indeed, I do see a need for that in the browser but that seems to be a
big no-no at the moment. I think I did find a quite elegant solution
that is *completely* in-line with Modules/1* (unlike the idea I posted
recently in another thread, which definitely wasn't - and without
ModuleObject or ExportsObject classes :-p). I can present it if one
would want me to (I have been keeping quiet on this not to create a
storm of ugly reactions), however I think this is not for this
thread. You know what, F* it, I don't care about the storm, I'll
present it anyways soon when I have a bit more time to put it on paper
in all its details. But something like this would certainly need
further discusssions while the 'require.ensure/.run' (or whatever else
one would want to call it) is a good quick solution that doesn't
require scraping, and doesn't break anything, and doesn't block future
evolution - ideal when time is of the essence.

Perhaps I missed some other arguments but from the ones that I did
pick up, I really think that the opinions are not so far apart and
that it can be 'that simple': 'require.load', 'require.define' and
'require.run' (or however you want to scope/namespace/name it -
personally I don't like connecting these things to 'module', but that
is again a different discussion :-) ).

Stefaan







Christoph Dorn

unread,
Oct 21, 2010, 5:49:56 PM10/21/10
to comm...@googlegroups.com
On 10-10-21 2:29 PM, Dean Landolt wrote:
> I do think we need to vote on an alternative source format that can
> be transformed into an acceptable transport format.
>
> I think it's a little bigger than this. If we're going to endorse and
> /alternate/ format the state of affairs is completely unchanged -- we

> now have two competing, non-interoperable module formats.

But they are interchangeable other than some restrictions for browser
loaders that cannot use script tag loading and must use XHR + eval or a
server-based transformation step for Modules/1.1.1.


> Which one do you author in? No heuristics can really answer that
> question (especially as browsers gain features).

My assumption was you use the 'wrapped' format if you think your module
will ever make it to the browser (that will be most open source library
modules and scripts). If you code strictly on the server or have a
server-helper or build step before distribution available you can code
in Modules/1.1.1 format as before.

The presence of the wrapper will also tell you if the script was ever
intended to run on the browser.

If there needs to be only one wrapped format so be it, but I am in
agreement with Kris Kowal that the need for the wrapper will disappear
in time at which point CommonJS/Modules without wrapper will feel like a
real programming language. The wrapped format does not.

Christoph

Dean Landolt

unread,
Oct 21, 2010, 5:51:43 PM10/21/10
to comm...@googlegroups.com
Can you elaborate on that workaround? If this proves to be completely true this could drastically reframe the debate.
 

*** No build-step to deploy:
I honestly don't see why this would be an absolute requirement.  If
somebody can load a 'script' on a server, then why wouldn't it be
possible to package the script and load the 'packaged script' on the
server?

*** Fragmentation browser <-> server
This is in my opinion a no-no and is not really needed AFAICT,
provided we can come to an agreement that items 2) and 4) higher
cannot be supported as currently defined in AMD.

If you have a build step what's the difference? You can build into a transport format -- and as has been pointed out several times, we don't all need to agree on transport formats -- there can be as many as folks have the energy to support. One would be great but as far as I can tell competing transport formats doesn't harm our ability to write interoperable modules. If a transport format supports extra features, don't use them if you want interoperability. Simple as that.
 

*** Packaging multiple modules in one file
This is still possible - I think the module-ID rules I wrote up higher
would solve that

*** Unifying transport/authoring/script-tags
I believe they are all 3 very much related but have semantics (esp
around security) that are different enough to warrant a separation.
But in the end, if people feel really really strong about this, then I
could live with unifying, provided there are solutions for the
security issue that don't create extra limitations.

*** moving declaration of dependencies to the module-author
Completely agree that there is a need for that (esp. when running from
script-tags).  This is essentially already availablein some form and
working on some platforms: 'require.ensure' - I would propose an
additional 'require.run' (or 'require.depend' or 'module.declare')
which is from a coding perspective identical to 'require.ensure' - *it
can be an alias* - but to be able to keep a separate 'require.ensure'
for *conditional* dynamic loading (which is BTW not really possible
when tools scrape for 'require'd module-IDs).  Also, this wrapper can
be dropped for modules that don't have any dependencies.  Finally,
just as 'require.ensure', this wrapper is essentially part of the code
- not a transport- or authoring-wrapper or packaging-wrapper.

This is where we get into Modules/2.0 territory.
 

*** exports-promises
Indeed, I do see a need for that in the browser but that seems to be a
big no-no at the moment.  I think I did find a quite elegant solution
that is *completely* in-line with Modules/1* (unlike the idea I posted
recently in another thread, which definitely wasn't - and without
ModuleObject or ExportsObject classes :-p).  I can present it if one
would want me to (I have been keeping quiet on this not to create a
storm of ugly reactions), however I think this is not for this
thread.  You know what, F* it, I don't care about the storm, I'll
present it anyways soon when I have a bit more time to put it on paper
in all its details.  But something like this would certainly need
further discusssions while the 'require.ensure/.run' (or whatever else
one would want to call it) is a good quick solution that doesn't
require scraping, and doesn't break anything, and doesn't block future
evolution - ideal when time is of the essence.

I think any idea you have that could allow script tag running that is compatible with Modules/1.1 would be very useful for this conversation, no matter how exotic or controversial. But it has to actually be compatible -- as in, the authoring format can be run in Modules/1.1 environments. Otherwise, again, we're in Modules/2.0 land.
 

Perhaps I missed some other arguments but from the ones that I did
pick up, I really think that the opinions are not so far apart and
that it can be 'that simple': 'require.load', 'require.define' and
'require.run' (or however you want to scope/namespace/name it -
personally I don't like connecting these things to 'module', but that
is again a different discussion :-) ).

It does sound like people are starting to coalesce around a ScriptModules module.define/module.declare style...but again, this is Modules/2.0 -- no matter how tempting it is to call it something else.

Stefaan

unread,
Oct 21, 2010, 5:54:26 PM10/21/10
to CommonJS
>
> > module.declare(["bar"], function (require, exports, module) {
> >    var bar = require("bar");
> >    exports.foo = function();
> > });
>

this is almost identical to 'require.ensure': +1
I would attach it to module because what if there is a real module-
object in the global scope?

>
> > as an *alternate source format* for Modules/2.0 with the following as the
> > default:
>

I don't see why this would need to be Modules/2* - if require.ensure
was considered for Modules/1*, why can't this be Modules/1*?

I don't understand what this would break in Modules/1*, unless you
would make the declaration mandatory but why would we do that. F.i.
when there are no dependencies, then this is not needed.
And as somebody else suggested, if no declaration, then dependencies
can still be scraped - only limitation would be that such a module
would not run from script-tags if it would have dependencies and if
these dependencies would not have been loaded before, right?

stefaan

jbrantly

unread,
Oct 21, 2010, 5:55:23 PM10/21/10
to CommonJS
On Oct 21, 2:49 pm, Christoph Dorn <christoph...@christophdorn.com>
wrote:
> My assumption was you use the 'wrapped' format if you think your module
> will ever make it to the browser (that will be most open source library
> modules and scripts). If you code strictly on the server or have a
> server-helper or build step before distribution available you can code
> in Modules/1.1.1 format as before.

This was almost my initial assumption. Just so that I don't have to
rehash stuff, this is the conversation where Wes convinced me and dean
that an alternative format isn't so good.

[17:11] <deanlandolt> what i didn't get was whether we could make the
boilerplate optional...
[17:11] <jbrantly> I think thats the case
[17:11] <deanlandolt> just because you /can/ author modules that can
be loaded in a script tag shouldn't mean you /must/
[17:12] <jbrantly> right
[17:12] <deanlandolt> oh? well good
[17:13] <WesMac> You can't make the boilerplate optional if you want
your module to be loadable in a script tag
[17:13] <WesMac> If you want script tags to load commonjs modules,
then, the spec must include the boilerplate
[17:13] <WesMac> :. boilerplate is not optional if we want to solve
this class of problems
[17:14] <deanlandolt> WesMac: why not? the spec can define and include
the boilerplate and say compliant loaders have to support it
[17:14] <WesMac> that said -- it is possible to create a CommonJS
environment which could load both MOdules/1.1 and Modules/2.0 modules,
for example
[17:14] <deanlandolt> but that doesn't mean modules must be authored
with boilerplate, right?
[17:14] <WesMac> deanlandolt: It does indeed! Otherwise we just have
Modules/1.1
[17:14] <deanlandolt> i guess i don't understand why a Modules/2.0
couldn't define boilerplate-optional modules
[17:15] <WesMac> Because they wouldn't work everywhere
[17:15] <jbrantly> hmm
[17:15] <jbrantly> he kinda has a point
[17:15] <deanlandolt> but they would...you just wouldn't be able to
use the script tag
[17:15] <deanlandolt> the script tag is /optional/
[17:15] <deanlandolt> hmm, crap, now that i think about it...
[17:15] <deanlandolt> yeah, i guess then everyone would just always
use the boilerplate
[17:15] <WesMac> Not to put too fine a point on it, but if you make
the boilerplate optional, then there is no point to MOdules/2.0
[17:16] <jbrantly> "by default", a non-define module would not be
runningable everywhere
[17:16] <deanlandolt> so why not just leave 1.1 and 2.0 in place and
allow them to work in harmony
[17:16] <WesMac> exacly
[17:16] <WesMac> exactly to jbrantly
[17:16] <WesMac> deanlandolt: That's certainly an option

Dean Landolt

unread,
Oct 21, 2010, 6:02:41 PM10/21/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 5:49 PM, Christoph Dorn <christ...@christophdorn.com> wrote:
On 10-10-21 2:29 PM, Dean Landolt wrote:
   I do think we need to vote on an alternative source format that can
   be transformed into an acceptable transport format.

I think it's a little bigger than this. If we're going to endorse and
/alternate/ format the state of affairs is completely unchanged -- we
now have two competing, non-interoperable module formats.

But they are interchangeable other than some restrictions for browser loaders that cannot use script tag loading and must use XHR + eval or a server-based transformation step for Modules/1.1.1.


I could buy that if we're not breaking support for Modules/1.1 it could just as easily be called Modules/1.2 -- but is the wrapped form a Module? If so we should bump the spec, right?

 



Which one do you author in? No heuristics can really answer that
question (especially as browsers gain features).

My assumption was you use the 'wrapped' format if you think your module will ever make it to the browser (that will be most open source library modules and scripts). If you code strictly on the server or have a server-helper or build step before distribution available you can code in Modules/1.1.1 format as before.


Sure, but I content that the line isn't clear -- it's tough to know precisely what modules you'll only use on the server...especially as browsers gain features.
 


The presence of the wrapper will also tell you if the script was ever intended to run on the browser.


This is a smell.

 

If there needs to be only one wrapped format so be it, but I am in agreement with Kris Kowal that the need for the wrapper will disappear in time at which point CommonJS/Modules without wrapper will feel like a real programming language. The wrapped format does not.

Yeah, I completely agree. I have absolutely no horse in this race (I can use transporter). But I maintain that we simply can't get away with two distinct modules formats -- formats you intend to author code in (even if you call one something else). We're talking about a new Modules spec, so let's do that.

Christoph Dorn

unread,
Oct 21, 2010, 6:04:07 PM10/21/10
to comm...@googlegroups.com
On 10-10-21 2:18 PM, Christoph Dorn wrote:
>> So I suppose I am still coming back to liking what was in AMD already,
>> but strengthening the language around the module ID as only being
>> there for transport, and it may be rejected for for security concerns,
>> and be very vocal about not encouraging people to hand code with a
>> module ID.

If you encourage:

define(["require", "exports", "module", "bar", "baz"],


function(require, exports, module, bar, baz) {

bar.foo();
});

as a source format the user must realize that they are not coding a
CommonJS module and the module will not be interoperable with other
loaders that do not also support this format. I don't think that is a
wise approach to encourage. It does not take much to add the require()
calls to get the module references within the module.

I also don't like this format as you need to line up the dependency
declarations and variables which gets confusing the more dependencies
you have.

Christoph

Christoph Dorn

unread,
Oct 21, 2010, 6:12:36 PM10/21/10
to comm...@googlegroups.com

Ok. I see.

I am fine with leaving 1.1 and 2.0 in place and allow them to work in
harmony.

Can we state that a 2.0 compliant loader must also support 1.1?

Christoph

jbrantly

unread,
Oct 21, 2010, 6:18:29 PM10/21/10
to CommonJS


On Oct 21, 3:12 pm, Christoph Dorn <christoph...@christophdorn.com>
wrote:
> Can we state that a 2.0 compliant loader must also support 1.1?

I personally would be in favor of this, but I don't know if there are
any technical reasons for saying no.

One thing I believe would need to be discussed is the mechanics for
how a loader can either
1) Distinguish between a 1.1 and 2.0 module or
2) Make sure 1.1 "just works" in a 2.0 environment

Wes Garland

unread,
Oct 21, 2010, 6:34:31 PM10/21/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 6:12 PM, Christoph Dorn <christ...@christophdorn.com> wrote:
Can we state that a 2.0 compliant loader must also support 1.1?

No. We can state that a 2.0 compliant loader MAY also support 1.1.  That's actually pretty easy to implement.

We should also state that a 1.1 module, wrapped inside a 2.0 module function *must* work exactly as it did in 1.1 once loaded.

But you can't insist that 2.0 loader support 1.1, because then you have the 1.1 restriction with respect to script-tag loading.  There is no way for a loader to know before it fetches a module which version it was built to work with, and by the time it's been loaded into the script tag, it's too late.

I think if we can establish a Modules/2.0 specification that fixes the issues discussed, along with a few other spec bugs from 1.1 and some features which have been tried out then we'll see implementors and module writers lining up to be 2.0 compliant -- because the versioning will clearly communicate the direction we intend to evolve.

Wes

Stefaan

unread,
Oct 21, 2010, 7:16:07 PM10/21/10
to CommonJS
I would like to answer to lots of the posts here, but let me take this
one first :-)

On Oct 21, 10:51 pm, Dean Landolt <d...@deanlandolt.com> wrote:
> On Thu, Oct 21, 2010 at 5:39 PM, Stefaan <stefaan.coussem...@advalvas.be>wrote:
>
> Can you elaborate on that workaround? If this proves to be completely true
> this could drastically reframe the debate.
>

on 2) injects in the factory-function:

If the injects are all module-IDs, then injecting them in the factory
function arguments is a nice to have. The plain old 'var
x=require("x")' works just as well as having a 'function(require,
exports, module,x)'. Be it that it perhaps doesn't look as nice as
injecting, and it is a bit more typing work, but this cannot really be
an argument since we are all doing much uglier stuff when writing
code. Something like this can definitely be deferred to Modules/2
IMO.

The only real problem comes when having things like plugins in the
dependencies, i.e. "txt!somefile.txt". Since these have no equivalent
to a module-ID, they cannot be 'require'd. Hence the AMD-solution to
inject them as an argument in the factory-function.
Now the workarounds:
a) one could make named plugins: "txt!myText=somefile.txt" and the
engine could add the results of these named plugins to the 'module'
object where it is available to the code as 'module.myText'. No
injects in the factory-arguments required.
b) if one doesn't want or can name the plugins, then you could have a
'module.plugins'-array, where these plugin-results are pushed onto and
thus can be accessed as 'var myText = module.plugins[i]' with 'i' is
the index in the dependencies-array. However, what should not be
allowed is that any real module-exports are also pushed into this
array.

on 4) returning exports that are not a plain {} object:
The common practise to add this as a property to the 'exports'. So
f.i. for a constructor, 'var x = new require("x").X()' instead of 'var
x = new require("x")();', or for a simple number 'var y =
require("y").value' instead of 'var y = require("y");'

all of this not nice etc... but perfectly workable in a Modules/1*
context.

side-note: AFAICT, plugins are *not* transport but authoring.

> > *** Fragmentation browser <-> server
> > This is in my opinion a no-no and is not really needed AFAICT,
> > provided we can come to an agreement that items 2) and 4) higher
> > cannot be supported as currently defined in AMD.
>
> If you have a build step what's the difference? You can build into a
> transport format -- and as has been pointed out several times, we don't all
> need to *agree* on transport formats -- there can be as many as folks have
> the energy to support. One would be great but as far as I can tell competing
> transport formats doesn't harm our ability to write interoperable modules.
> If a transport format supports extra features, don't use them if you want
> interoperability. Simple as that.

Agreed - but I wasn't alluding to transport here - I do think that
there should be no fragmentation on the other things.

> > *** exports-promises
> > Indeed, I do see a need for that in the browser but that seems to be a
> > big no-no at the moment.  I think I did find a quite elegant solution
> > that is *completely* in-line with Modules/1* (unlike the idea I posted
> > recently in another thread, which definitely wasn't - and without
> > ModuleObject or ExportsObject classes :-p).  I can present it if one
> > would want me to (I have been keeping quiet on this not to create a
> > storm of ugly reactions), however I think this is not for this
> > thread.  You know what, F* it, I don't care about the storm, I'll
> > present it anyways soon when I have a bit more time to put it on paper
> > in all its details.  But something like this would certainly need
> > further discusssions while the 'require.ensure/.run' (or whatever else
> > one would want to call it) is a good quick solution that doesn't
> > require scraping, and doesn't break anything, and doesn't block future
> > evolution - ideal when time is of the essence.
>
> I think any idea you have that could allow script tag running that is
> compatible with Modules/1.1 would be very useful for this conversation, no
> matter how exotic or controversial. But it has to actually be *compatible* --
> as in, the authoring format can be run in Modules/1.1 environments.
> Otherwise, again, we're in Modules/2.0 land.
>

OK, let me give the highlights:

on the provider side:
- 'exports' or for initial (partial?) exports as is the case now
- 'exports' can only be used during the first turn of the module-
factory, or more restrictive but safer: can only be used outside of
callback-functions.
- we add 'module.setExports' and 'module.getExports'.
- any changes to the exports that happen inside callback functions
should use the getter/setter.
- as long as 'exports' are not 'require'd by another module, this
getter/setter changes the 'exports'.
- as soon as 'exports' are 'require'd, the public 'exports' are copied
to the privileged exports, i.e. a hidden object that is only
accessible via the getter/setter.
- optionally: a default property could be added to the public
'exports' so a consumer can test if it can expect more:
'exports.isPromise = function () { return true; }.
- after this copy, the getter/setter works on the privileged exports,
the public 'exports' are frozen (and can be effective frozen in ES5).
- a new function 'module.resolve(theError)' is added to resolve or
reject the exports-promise.

on the consumer side:
- a new function 'require.resolved(theRequiredId,
onResolved(theResolvedId, theResolvedExports))' is added for the
consumer to get the exports-promise, depending on the status of the
required module.

for cyclic dependencies:
- a new function 'require.update(theRequiredId,
onUpdated(theUpdatedId, theUpdatedExports)) is added for the cyclic
dependent module to get partial updates for the exports-promise.

for compatibility with a promises-module:
- optional: a new function 'require.promise(theRequiredId)' which
packs the privileged exports into a promise-object and returns it.

There are some other considerations to be made to make this work
seemless with modules that were coded without the use of export-
promises, both on consumer and provider side but these are details,
but I'm afraid I'll have to leave this for another day since it's
already past midnight here in UK.

But essentially, with all the above, I believe I didn't break any of
the Module/1* rules - except perhaps for the use of getter/setter
instead of direct assignment to an 'export'-property, which is AFAICT
harmless.

>
> > Perhaps I missed some other arguments but from the ones that I did
> > pick up, I really think that the opinions are not so far apart and
> > that it can be 'that simple': 'require.load', 'require.define' and
> > 'require.run' (or however you want to scope/namespace/name it -
> > personally I don't like connecting these things to 'module', but that
> > is again a different discussion :-) ).
>
> It does sound like people are starting to coalesce around a ScriptModules
> module.define/module.declare style...but again, this is Modules/2.0 -- no
> matter how tempting it is to call it something else.- Hide quoted text -

Don't agree that this would be Modules/2.0, unless you make this a
mandatory requirement.
In my opinion there is no real difference with 'require.ensure', you
could even do something like 'require.run = require.ensure'.
Also, this 'require.run' is obsolete for modules that have no
dependencies.

BTW, I am still using 'require.run' (but 'require.declare' would be as
good), because I don't think it is a good idea to attach it to
'module' - sorry Wes :-).
I for one was expecting to add a module-object to the global scope and
consider the global scope as a module in it's own right - but this is
not a breaking point.

Christoph Dorn

unread,
Oct 21, 2010, 7:20:25 PM10/21/10
to comm...@googlegroups.com
On 10-10-21 3:34 PM, Wes Garland wrote:
> On Thu, Oct 21, 2010 at 6:12 PM, Christoph Dorn
> <christ...@christophdorn.com <mailto:christ...@christophdorn.com>>

> wrote:
>
> Can we state that a 2.0 compliant loader must also support 1.1?
>
> No. We can state that a 2.0 compliant loader MAY also support 1.1.
> That's actually pretty easy to implement.
>
> We should also state that a 1.1 module, wrapped inside a 2.0 module
> function *must* work exactly as it did in 1.1 once loaded.
>
> But you can't insist that 2.0 loader support 1.1, because then you have
> the 1.1 restriction with respect to script-tag loading. There is no way
> for a loader to know before it fetches a module which version it was
> built to work with, and by the time it's been loaded into the script
> tag, it's too late.
>
> I think if we can establish a Modules/2.0 specification that fixes the
> issues discussed, along with a few other spec bugs from 1.1 and some
> features which have been tried out then we'll see implementors and
> module writers lining up to be 2.0 compliant -- because the versioning
> will clearly communicate the direction we intend to evolve.

+1

So can we assume we have a consensus for this direction and stop
discussing this matter in the current open-ended threads?

I suggest someone draft up a proposal for Modules 2.0 with the spec bugs
fixed and features added and frame a discussion around that. I run for
the hills when it comes to writing these specs with the appropriate
terminology otherwise I would volunteer.

In the discussions stefaan raised some issues regarding separation of
concerns and plugins for module loading etc.. which were not really
discussed. I suggest we postpone that discussion until we have a Modules
2.0 proposal to frame it and people have had a chance to collect their
thoughts and get some work done :)

Christoph

Stefaan

unread,
Oct 21, 2010, 7:25:55 PM10/21/10
to CommonJS


On Oct 21, 11:34 pm, Wes Garland <w...@page.ca> wrote:
> On Thu, Oct 21, 2010 at 6:12 PM, Christoph Dorn <
>
> christoph...@christophdorn.com> wrote:
> > Can we state that a 2.0 compliant loader must also support 1.1?
>
> No. We can state that a 2.0 compliant loader MAY also support 1.1.  That's
> actually pretty easy to implement.
>
> We should also state that a 1.1 module, wrapped inside a 2.0 module function
> *must* work exactly as it did in 1.1 once loaded.
>
> But you can't insist that 2.0 loader support 1.1, because then you have the
> 1.1 restriction with respect to script-tag loading.  There is no way for a
> loader to know before it fetches a module which version it was built to work
> with, and by the time it's been loaded into the script tag, it's too late.
>

yes there is - use a plugin in the dependencies, along the line "cjs!
1.1" or "cjs!2.0", for the developer to specify which version he is
using, or in the transport case for the buider to do the same
(assuming it can easily be scraped based on the 'require'- and
'module' property names it uses ). this was exactly what I meant when
I was posting about pragmas last week.

Stefaan

Wes Garland

unread,
Oct 21, 2010, 7:37:09 PM10/21/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 7:25 PM, Stefaan <stefaan.c...@advalvas.be> wrote:

yes there is - use a plugin in the dependencies, along the line "cjs!
1.1" or "cjs!2.0", for the developer to specify which version he is
using

IMHO there is no need for that.  If the module user is specifying which type of module the loader is loading, he can just specify an alternate loader instead.

I am VERY uncomfortable suggesting two standards for authoring modules.  And the transports scraper issue is a red herring, if this could be solved with a server-side process we would not be having this discussion.

Wes

felix

unread,
Oct 21, 2010, 6:13:21 PM10/21/10
to comm...@googlegroups.com, Stefaan
On 10/21/10 14:39, Stefaan wrote:
> *** No build-step to deploy:
> I honestly don't see why this would be an absolute requirement. If
> somebody can load a 'script' on a server, then why wouldn't it be
> possible to package the script and load the 'packaged script' on the
> server?

some webdev environments are serverless. right now, it's possible to
edit a js file on your local filesystem, save, hit refresh in the
browser, and it works. some environments have save-and-refresh as a
single action.

save-and-build-and-refresh can be imperceptibly slower, but setting up a
build step is extra hassle, it's going to alienate people.

khs4473

unread,
Oct 21, 2010, 9:19:05 PM10/21/10
to CommonJS
I'll wait for the 2.0 spec before making any more blithe remarks
(although it will be difficult to restrain myself). Are we going to
try to tackle some other bits in 2.0 as well (like setExports - I
think we might be able to get that one in)?

Wes Garland

unread,
Oct 21, 2010, 9:52:33 PM10/21/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 6:13 PM, felix <fel...@gmail.com> wrote:
some webdev environments are serverless.  right now, it's possible to edit a js file on your local filesystem, save, hit refresh in the browser, and it works.  some environments have save-and-refresh as a single action.

This is well understood. What is not well is understood is why those folks can't use XHR. But I think this is now a moot point.
 
Wes

Christoph Dorn

unread,
Oct 21, 2010, 10:01:33 PM10/21/10
to comm...@googlegroups.com
On 10-10-21 6:52 PM, Wes Garland wrote:
> On Thu, Oct 21, 2010 at 6:13 PM, felix <fel...@gmail.com
> <mailto:fel...@gmail.com>> wrote:
> some webdev environments are serverless. right now, it's possible
> to edit a js file on your local filesystem, save, hit refresh in the
> browser, and it works. some environments have save-and-refresh as a
> single action.
>
> This is well understood. What is not well is understood is why those
> folks can't use XHR. But I think this is now a moot point.

I am sure this will be rehashed as part of the Modules/2.0 spec
discussion and having a concise argument for completeness and
justification of the change is necessary anyway.

Christoph

James Burke

unread,
Oct 22, 2010, 2:07:57 AM10/22/10
to comm...@googlegroups.com
On Wed, Oct 20, 2010 at 6:40 PM, Wes Garland <w...@page.ca> wrote:
> The module.dependencies proposal I put forward earlier this week is
> incomplete and does not pass the CommonJS module test suite, however I am
> working on another solution which I'm confident will work.  This solution,
> however, requires reading a small amount of the module's text before
> executing it. This solution is also verifiable no risk of script-scraping
> parse errors.
>
> Do you have any experience and/or insight to offer here?  Do you know of a
> module-oriented way to annotate dependencies which can be used effectively
> at run time? How does RequireJS solve the transitive test program problem?
> (Can RequireJS run the test suite?)

I did not follow all of what you wrote before about a depend(), and
callee vs caller on dependencies, but I believe what RequireJS
implements, and what was outlined in as anonymous define calls in the
AMD proposal addresses your concerns. You asked about RequireJS
passing the test suite. I assume you mean the CommonJS modules 1.0
tests found here:

http://github.com/commonjs/commonjs/tree/master/tests/modules

I took those and converted them to the format understood by RequireJS:
anonymous define() calls with a dependency list. I ran the modules
through the convertCommonJs.sh program I have that adds the define()
wrapper, then I added a program.html to each test folder and made a
test.js and system.js for the browser. I put the code up here:

http://github.com/jrburke/requirejs/tree/master/tests/commonjs/tests/modules/1.0/

You can run them here (click each one individually and be sure to have
the console open in the browser):

http://www.requirejs.org/temp/requirejs-cjs/tests/commonjs/tests/modules/1.0/all.html

(warning, those tests are in a temp directory which may disappear at
some point. The files are available via the github url if it does go
away).

These tests pass with RequireJS with this qualification: "missing" and
"determinism" make reference to modules that do not exist. The tests
assume that the require("") will throw, but what happens in the async
script-tag env for RequireJS, dependencies are loaded before executing
the test. Since those dependencies never load, the test does not get
run. After 7 seconds (default wait time for RequireJS) it will throw
an error saying it could not load a module. There is not a way to know
via JavaScript/DOM if a script tag fails due to network issues or a
404, so a timeout is used. In both cases the paths used to load the
bogus modules were correct according to the module ID-to-path
expectations.

So I believe it passes the spirit of those two tests -- error when a
dependency is not available.

James

James Burke

unread,
Oct 22, 2010, 2:52:36 AM10/22/10
to comm...@googlegroups.com
On Thu, Oct 21, 2010 at 1:54 PM, jbrantly <jbra...@sent.com> wrote:
> I understand your strong desire to use fun stuff like injects and
> return exports, but in the spirit of cooperation, since those things
> (I don't believe) have been totally agreed upon, can we set them aside
> or at least make them less important than the larger goal of getting
> an authoring module format that's loadable via <script>?

Sure. That seems to condense the proposal to:

define(function (require, exports, module){
});

Specifying an array of dependencies before the function implies the
discussion around injection. Node has a export setting now, and it
comes up enough to warrant specification, but in the interests of
getting something identified as general agreement, it can be left out
for now. I still plan on supporting those things in my implementation.

The above form should come with a note about it being a problem for
some envs without a usable Function.prototype.toString, and that a
transport format will be recommended to use code in those browsers. So
far that seems like Opera Mobile and PS3. The ES spec allows for
future implementations to deliver something with a unusable toString,
but hopefully if this format gains traction, those implementations
will be asked to correct it before release.

I am not sure what is gained by using module.define or module.declare
as the global entry point name, so I used define up above.

It also seems like there is a desire to *not* specify the transport
parts at this time. Those bits can be left out of this particular
proposal, but given that I support a transport format now, I would
probably want to spec it out in some proposal, since the RequireJS,
Nodules and dojo-sie loaders use it already. Maybe that means just
taking those bits from of the AMD page and updating the Transport/C
proposal, and let things cool down for a while.

James

Stefaan

unread,
Oct 22, 2010, 4:07:12 AM10/22/10
to CommonJS
Just a couple of things where a changed my mind after a long and
sleepless ;-) night of thinking about it.

On Oct 22, 12:16 am, Stefaan <stefaan.coussem...@advalvas.be> wrote:
>
> ...
>

> side-note: AFAICT, plugins are *not* transport but authoring.

I do now see a use for plugins in transport: specifying module-
specific meta-data that a server-side builder scrapes from the code.
There can be other ways to provide such module-meta-data, but plugins
is a good and very simple initial work-around for something more
complex that can be designed at a later time.
And it could be made really very easy - wrote a post on that
yesterday.

Dependencies are such meta-data, but there is much more that a loader
could need to properly load/define/execute a module. Such as:
- is the module using Modules/1.1.1 or Modules/2.0 -> "cjs!CommonJS/
Modules/1.1.1", "cjs!CommonJS/Modules/2.0", etc...
- does it use Modules/Async/A
- does it use Modules/setExports
- etc..

In the end, these CommonJS versions and extensions could (and IMO
should) be considered as a kind of module (or plugin) in their own
right - CommonJS should eat its own S*.
This will prove invaluable as CommonJS grows (more below)... you mark
my words :-).

A buidling step can then scrape the code for specific primitives (aka.
duck-typing) to determine these CommonJS-plugins and provide it to the
loader in its 'define'.

Alternatively, an author can declare it himself (aka. human scraping)
in his 'module.declare'.

And this all ties in with the other discussion about backward
compatibility etc...
As the Modules eco-system grows, there will be a real need to get
CommonJS-namespacing (and -versioning, although this can be solved by -
namespacing) sorted and specify how to use this.
There will always be server-engines and client-engines that are at
different stages of support for some of these CommonJS-modules (aka.
feature-sets).
And to make these work seemlessly, you will need some extra module-
specific meta-data, in the form of plugins or other.

> BTW, I am still using 'require.run' (but 'require.declare' would be as
> good), because I don't think it is a good idea to attach it to
> 'module' - sorry Wes :-).
> I for one was expecting to add a module-object to the global scope and
> consider the global scope as a module in it's own right - but this is
> not a breaking point.- Hide quoted text -

Changed my mind on this one too :-)

The way I see it, the Modules eco-system provides really 3 APIs:
- 'define' for the module provider (aka the server, aka transport)
- 'require' for the module-exports consumer
- 'module' (and 'exports' as a shortcut for 'module.exports') for the
module-exports provider (aka. the module developer/author).

authoring does indeed fit in the module-exports provider area, hence
use the 'module' root.

> Don't agree that this would be Modules/2.0, unless you make this a
> mandatory requirement.
> In my opinion there is no real difference with 'require.ensure', you
> could even do something like 'require.run = require.ensure'.
> Also, this 'require.run' is obsolete for modules that have no
> dependencies

*but* I still don't agree with this one.
I understand that the going argument is that not *all* modules would
work from script-tag if this authoring-wrapper was not made mandatory,
hence Modules/2.0.
But...
We had a very similar discussion when talking about forcing
synchronous systems to always present/use an async API. There it was
deemed perfectly acceptable that there will be modules that are
written for synchronous loaders and thus will not run as expected when
used in an async loader.
So why do we not only make the browser a 1st class citizen but even a
1st class *VIP* citizen?

Stefaan

Stefaan

unread,
Oct 22, 2010, 4:24:07 AM10/22/10
to CommonJS


On Oct 22, 12:37 am, Wes Garland <w...@page.ca> wrote:
> On Thu, Oct 21, 2010 at 7:25 PM, Stefaan <stefaan.coussem...@advalvas.be>wrote:
>
>
>
> > yes there is - use a plugin in the dependencies, along the line "cjs!
> > 1.1" or "cjs!2.0", for the developer to specify which version he is
> > using
>
> IMHO there is no need for that.  If the module user is specifying which type
> of module the loader is loading, he can just specify an alternate loader
> instead.

But...
just as moving the specification of dependencies from user/loader to
the author, this is not for the module-user but for the module-author.
in the end, the specs that are supported/used by a module are just
another type of module-specific meta-data, just like dependencies are
meta-data.

>
> I am VERY uncomfortable suggesting two standards for authoring modules.  And
> the transports scraper issue is a red herring, if this could be solved with
> a server-side process we would not be having this discussion.
>

Not sure I follow - I think we are on a different wave-length, here -
I am not suggesting 2 standards for authoring. Only suggesting to add
extra meta-data to 'module.declare', in addition to the well accepted
module-dependencies meta-data.

... well... I am suggesting 2 standards :-) but that 2nd one is not
being discussed (yet) - that's why I proposed to make a distinction
between "authoring without running" (aka 'require.define') and
"authoring with running" (aka. 'module.declare' to run f.i. from
script-tags) - but I was kind of dropping the 2nd one for now, not to
add to the confusion/fire/etc...

Stefaan

Stefaan

unread,
Oct 22, 2010, 4:47:34 AM10/22/10
to CommonJS
On Oct 22, 2:19 am, khs4473 <khs4...@gmail.com> wrote:
> I'll wait for the 2.0 spec before making any more blithe remarks
> (although it will be difficult to restrain myself).  Are we going to
> try to tackle some other bits in 2.0 as well (like setExports - I
> think we might be able to get that one in)?
>
> On Oct 21, 6:13 pm, felix <feli...@gmail.com> wrote:

yes, please

My wish-list on top of the ongoing discussions in the thread would be
- setExports and exports-promises (effectively an extension of
setExports)
- async/A (aka 'require.ensure')
- using modules with asynchronous module-factories (aka. an extension
on async loading and an extension on exports-promises)
- conditional loading (since current 'require' scraping doesn't allow
'require.ensure' to do this)
- plugins or some other way to provide module-specific meta-data
- authoring without executing (aka 'require.define')
- handling of CommonJS-modules (aka partial support in client-engine
and server-engine - *not* to be confused with the 'commons'-module
being discussed in one of the other threads)
- ... and prob some more
Looks all very cumbersome and complicated but really isn't, these can
build on what's already there and each of these can and should be made
optional.

And when you have all of this sorted, only then you will really have a
complete and viable system that fits every (or most) environment and
that can be widely adopted... you mark my words :-p

However, no need to bump the major version - IMO all this can and does
work within Modules/1* :-)
Modules/2* should only happen when making a major break with the past,
some violation of one of the core principles behind Modules/1*,
- when allowing exports to be something else than a plain {},
- when allowing module-exports to be injected in a module's factory-
arguments.
- ...
Otherwise it can and should be considered an optional Modules-feature.

Anyways, only my opinion, :-)

Stefaan

Wes Garland

unread,
Oct 22, 2010, 8:39:40 AM10/22/10
to comm...@googlegroups.com
> Modules/2* should only happen when making a major break with the past,

You mean like publishing a specification such that correctly-written modules throw exceptions when loaded in Modules/1.1 infrastructure?

khs4473

unread,
Oct 22, 2010, 8:48:26 AM10/22/10
to CommonJS
Q1: Isn't the dependency array necessary for you to resolve
dependencies, since toString() isn't universally reliable?

Also, this function won't necessarily be global for systems that
provide the correct lexical scope for modules already. It will be
scoped to the module, and will probably just forward in the (already)
scoped require, exports, and module variables (that's how I've got
FlyScript doing it, anyway).

If it's scoped, then the options are to create a new scoped variable
("define") which will have to be attached to every factory function in
transport, or to attach it to "module". We're considering adding
"setExports" to module anyway, and this function seems to be in the
same spirit. Also, attaching it to module allows us to conveniently
detect whether wrapped modules are supported by the environment. And
I believe that we should avoid adding a new free variable to the mix
if we can.

Q2: Is having a "module" global variable for your system technically
infeasible?

Thanks, James!


On Oct 22, 2:52 am, James Burke <jrbu...@gmail.com> wrote:

Wes Garland

unread,
Oct 22, 2010, 8:58:58 AM10/22/10
to comm...@googlegroups.com
On Fri, Oct 22, 2010 at 8:48 AM, khs4473 <khs...@gmail.com> wrote:
Q1:  Isn't the dependency array necessary for you to resolve
dependencies, since toString() isn't universally reliable?

It's absolutely necessary if you're loading via script tags.  If you are loading via files or XHR, you can scan the code for dependencies before executing it.

Scanning the code for dependencies in a /1.1 can also be verified to be correct by placing the dependencies in an array module.dependencies, and verifying that the scanned list matches the declared list after the module is executed.  Forcing the location of module.dependencies to the top of the module (allowing for ES-5 and ES-next modes) also limits the time and memory used when scanning for dependencies, which does matter on very large modules like env.js.
 
Also, this function won't necessarily be global for systems that
provide the correct lexical scope for modules already.

That is correct. GPSEE executes modules in such a scope.  To browser folks, my global object is basically "window" for each object, and new modules do something like "window.open" and I have a resolve function between parent and child to resolve global variables.

The resolve function between modules allows me to selectively chose which symbols are available to modules, allowing me to implement, for example, sandboxes. Or to implement a principal-based security system at the module-scope boundary.
 
Q2:  Is having a "module" global variable for your system technically
infeasible?

You can't implement modules with a global variable, as module.id must vary per module.

Wes

khs4473

unread,
Oct 22, 2010, 9:07:23 AM10/22/10
to CommonJS
Sorry, impatient again...

Regarding injections: While they are convenient, I think it's
important that we design wrapped modules so that they can be trivially
unwrapped, and that we maintain this invariant (where WM is a wrapped
module and wrap/unwrap are our conversion functions):

wrap(unwrap(WM)) = WM

(Leading and trailing whitespace could be different). Anyway,
injections are going to prevent that.

khs4473

unread,
Oct 22, 2010, 9:10:53 AM10/22/10
to CommonJS
> You can't implement modules with a global variable, as module.id must vary
> per module.

Right - but since script tags are running in the global scope, he'll
need to "fake" the scoped "module" variable. It wouldn't have an id
property, just the declare() method.


On Oct 22, 8:58 am, Wes Garland <w...@page.ca> wrote:

Kris Zyp

unread,
Oct 22, 2010, 9:19:52 AM10/22/10
to comm...@googlegroups.com, James Burke

On 10/22/2010 12:52 AM, James Burke wrote:
> On Thu, Oct 21, 2010 at 1:54 PM, jbrantly <jbra...@sent.com> wrote:
>> I understand your strong desire to use fun stuff like injects and
>> return exports, but in the spirit of cooperation, since those things
>> (I don't believe) have been totally agreed upon, can we set them aside
>> or at least make them less important than the larger goal of getting
>> an authoring module format that's loadable via <script>?
> Sure. That seems to condense the proposal to:
>
> define(function (require, exports, module){
> });
>
> Specifying an array of dependencies before the function implies the
> discussion around injection. Node has a export setting now, and it
> comes up enough to warrant specification, but in the interests of
> getting something identified as general agreement, it can be left out
> for now. I still plan on supporting those things in my implementation.
>
> The above form should come with a note about it being a problem for
> some envs without a usable Function.prototype.toString, and that a
> transport format will be recommended to use code in those browsers. So
> far that seems like Opera Mobile and PS3.

The function toString limitation is noted in the spec. If it needs
clarification, feel free to update it (assume it would just be an
editorial change).

--
Thanks,
Kris

khs4473

unread,
Oct 22, 2010, 9:34:22 AM10/22/10
to CommonJS
> The above form should come with a note about it being a problem for
> some envs without a usable Function.prototype.toString, and that a
> transport format will be recommended to use code in those browsers

Sorry - I missed this the first time around. We're trying to get away
from recommending that anyone code in a transport format. We want
everyone coding in one format (Modules/2, presumably), whether wrapped
or not. I think that in the spec we should err or the side of
inclusiveness and generality. If your system can scarp
function.toString() for dependencies, that's great, but if not you can
fallback to the dependency array.

I think that we should specify that wrapped modules always be written
with a dependency array, if there are are dependencies (other than
require, exports, and module, of course). The dependency array would
be informational only from the point of view of the loader.

Agree/disagree?


On Oct 22, 2:52 am, James Burke <jrbu...@gmail.com> wrote:

Stefaan

unread,
Oct 22, 2010, 9:35:40 AM10/22/10
to CommonJS
Not sure I understand exactly - why would a correctly-written module
throw an exception?.
perhaps you mean, loading a 2.0 module in a 1.1 environment? But then
it is a badly-written module for 1.1, no? and thus an exception would
be correct.

I meant like:
- exports that can be something else than a plain {} object
- injecting module-exports in a factory-arguments so you don't need to
do a 'var x = require("x");' anymore.

On the other hand, if we are correcting a mistake/bug in the spec,
then that would be a patch version -> Modules/1.1.1
I think there was something like that with 'main' going from the
module to module-ID or something like that (would have to go back to
the specs and compare them).

My point is that minor version should guarantee backward compatibility
- major version doesn't (but hopefully does properly document where it
breaks bwd compat so people know how to convert their code).

In the commercial world, companies are often bumping major version for
marketing reasons (i.e. to be able to announce a new feature-set and
make a lot of noice around it), while still remaining bwd compat. But
CommonJS doesn't need this, right.

Stefaan

unread,
Oct 22, 2010, 9:46:25 AM10/22/10
to CommonJS


On Oct 22, 2:34 pm, khs4473 <khs4...@gmail.com> wrote:
> > The above form should come with a note about it being a problem for
> > some envs without a usable Function.prototype.toString, and that a
> > transport format will be recommended to use code in those browsers
>
> Sorry - I missed this the first time around.  We're trying to get away
> from recommending that anyone code in a transport format.  We want
> everyone coding in one format (Modules/2, presumably), whether wrapped
> or not.  I think that in the spec we should err or the side of
> inclusiveness and generality.  If your system can scarp
> function.toString() for dependencies, that's great, but if not you can
> fallback to the dependency array.

+1

>
> I think that we should specify that wrapped modules always be written
> with a dependency array, if there are are dependencies (other than
> require, exports, and module, of course).  The dependency array would
> be informational only from the point of view of the loader.

*should*: +1
*must*: not so sure. that would imply you make the browser a 1st
class *VIP* citizen.

sorry to come back on this but I still don't understand why such a
'module.declare'-wrapper cannot be optional.
> > James- Hide quoted text -
>
> - Show quoted text -

khs4473

unread,
Oct 22, 2010, 9:56:00 AM10/22/10
to CommonJS
> sorry to come back on this but I still don't understand why such a
> 'module.declare'-wrapper cannot be optional.

It would. There would presumably be one format, but two "idioms" (we
should work on nomenclature - it's important): wrapped and unwrapped.
Environments that can't natively provide lexical scoping for modules
would only support wrapped modules (and transports, but that's a
different story).

Wes Garland

unread,
Oct 22, 2010, 10:13:34 AM10/22/10
to comm...@googlegroups.com
On Fri, Oct 22, 2010 at 2:07 AM, James Burke <jrb...@gmail.com> wrote:
You asked about RequireJS
passing the test suite. I assume you mean the CommonJS modules 1.0
tests found here:

http://github.com/commonjs/commonjs/tree/master/tests/modules

Yes.  Although I think I pulled my tests from Kris Kowal's clone; they were originally part of the InteroperableJS project waaaay back when.
 
I took those and converted them to the format understood by RequireJS:
anonymous define() calls with a dependency list. I ran the modules
through the convertCommonJs.sh program I have that adds the define()
wrapper, then I added a program.html to each test folder and made a
test.js and system.js for the browser. I put the code up here:

http://github.com/jrburke/requirejs/tree/master/tests/commonjs/tests/modules/1.0/

Thanks!  I had a look through your finished files and they also cleared up some other questions I had.

If CommonJS produces a Modules/2.0 specification such that modules
  • Can be loaded directly in script tags without pre-processing
  • Supports asynchronous module loading
  • Expresses dependencies without scraping
Would you be willing to support it?

These tests pass with RequireJS with this qualification: "missing" and
"determinism" make reference to modules that do not exist.

Right. In particular determinism wants to insure that you don't accidentally use "./a" when "a" is called for and require("a") !== require("./a").

So, your behaviour is definitely close enough to a pass that I wouldn't quibble over details.

That said, this leads a little bit toward the separation of concerns that I discussed briefly in my essay-length e-mail on Monday.  When de-referencing the module memo also provides modules --  overloading require() -- you have a situation where you cannot throw from require, which is how CommonJS environments communicate missing-module errors.

The tests
assume that the require("") will throw, but what happens in the async
script-tag env for RequireJS, dependencies are loaded before executing
the test.

To be clear, they assume that require("INVALID MODULE NAME") will throw.
 
Since those dependencies never load, the test does not get
run. After 7 seconds (default wait time for RequireJS) it will throw
an error saying it could not load a module. There is not a way to know
via JavaScript/DOM if a script tag fails due to network issues or a
404, so a timeout is used.

Ah, yes, that's right: you cannot know when using script-tags that a resource was not found.
 
So I believe it passes the spirit of those two tests -- error when a
dependency is not available.


Well, one of them actually to want error if you mis-calculate your dependency name, and you don't, so that's a pass.

Wes

Chris Zumbrunn

unread,
Oct 22, 2010, 10:24:05 AM10/22/10
to comm...@googlegroups.com
On Fri, Oct 22, 2010 at 00:02, Dean Landolt <de...@deanlandolt.com> wrote:
>
> On Thu, Oct 21, 2010 at 5:49 PM, Christoph Dorn
> <christ...@christophdorn.com> wrote:
>>
>> If there needs to be only one wrapped format so be it, but I am in
>> agreement with Kris Kowal that the need for the wrapper will disappear in
>> time at which point CommonJS/Modules without wrapper will feel like a real
>> programming language. The wrapped format does not.
>
> Yeah, I completely agree. I have absolutely no horse in this race (I can use
> transporter). But I maintain that we simply can't get away with two distinct
> modules formats -- formats you intend to author code in (even if you call
> one something else). We're talking about a new Modules spec, so let's do
> that.

I agree this whole "wrapper thing" is a temporary beast. Basing
Modules 2.0 on it gains us little.

Thinking that declaring a wrapped module format as Modules 2.0 will
result in everybody working directly in that wrapped format, and that
as a result we'll only have a single unified format, is an illusion.
Specially if the unwrapped format is deprecated, it will open the
doors for several different unwrapped formats to emerge, which will be
used within different environments without a need for boilerplate, and
the CommonJS format will effectively "only" be a transport format.
This will fragment the community more than if we would ratify a
CommonJS Module Wrapper 1.x format in addition to the CommonJS Module
1.x format.

You can't force people to work with their code in files containing
boilerplate any more than you can force people not to directly fiddle
around with code in a wrapper format :-)

Chris

Kevin Dangoor

unread,
Oct 22, 2010, 10:33:00 AM10/22/10
to comm...@googlegroups.com
On Fri, Oct 22, 2010 at 10:24 AM, Chris Zumbrunn <ch...@zumbrunn.com> wrote:

Thinking that declaring a wrapped module format as Modules 2.0 will
result in everybody working directly in that wrapped format, and that
as a result we'll only have a single unified format, is an illusion.

Thankfully, I don't believe the current discussion says that at all, and I won't blame anyone for not keeping up with this looong set of threads.

Specifically, Modules 2.0 would acknowledge that some environments don't support the unwrapped format and specify that you must use the wrapped format if you want to support such environments (eg browsers).

People writing Node, Jetpack, GPSEE, Persevere, RingoJS, etc. modules will be free to continue using the unwrapped format.

Kevin

--
Kevin Dangoor

work: http://mozilla.com/
email: k...@blazingthings.com
blog: http://www.BlueSkyOnMars.com

Wes Garland

unread,
Oct 22, 2010, 10:39:35 AM10/22/10
to comm...@googlegroups.com
On Fri, Oct 22, 2010 at 2:52 AM, James Burke <jrb...@gmail.com> wrote:
Specifying an array of dependencies before the function implies the
discussion around injection.

It's certainly not arbitrary object injection.  It merely ensures that the module is not executed until it can resolve require(X) for each X in the dependency array.
 
The above form should come with a note about it being a problem for
some envs without a usable Function.prototype.toString,

I hope I never live to see the day where we have to toString() a module to find dependencies in a core CommonJS specification.
 
I am not sure what is gained by using module.define or module.declare
as the global entry point name, so I used define up above.

The obvious one is namespacing, but eliminating the global variable also eases transition from 1.1 to 2.0 module systems, especially in implementations which want to allow both module formats.  The trick is to set up a /1.1 module environment with all dependencies satistfied, free require, exports, and module, then execute the 2.0 module.  Since we now have a unique module.declare attached to the /1.1 module, we can hoist the 2.0 module up by it's own bootstraps.

Recall, that I pointed out in my e-mail on Monday that blocking-friendly /1.1 systems have the luxury of being able to always behave as though all dependencies have already been loaded.  Specifying module.declare() as I have suggested makes migrating /1.1 to /2.0 extremely simple for server-side systems.  Possibly as simple as this:

module.prototype.declare = function (deps, moduleFunction) {
  moduleFunction();
}

Also, speciffying module and exports as instances of something other than Object allows users to monkey patch the CommonJS Environment to add future capabilities.

It also seems like there is a desire to *not* specify the transport
parts at this time

From my perspective, Transports need to be specifyied only when multiple vendors want to interoperate.   The core of CommonJS is the module authoring format, and it must specified so that portable code can be written to run on all platforms.  The spec must also be identified properly so that module authors know what format to write in.  Encouraging users to write code in a transport format is not productive.
 
Those bits can be left out of this particular
proposal, but given that I support a transport format now, I would
probably want to spec it out in some proposal, since the RequireJS,
Nodules and dojo-sie loaders use it already. Maybe that means just
taking those bits from of the AMD page and updating the Transport/C
proposal, and let things cool down for a while.

I see great value in specifying a transport format that multiple vendors can make use of.  Everybody wins when we have software interoperability.

However, support for a particular transport format is by definition optional, whereas support for the current module format is not.

Wes Garland

unread,
Oct 22, 2010, 10:45:33 AM10/22/10
to comm...@googlegroups.com
On Fri, Oct 22, 2010 at 10:33 AM, Kevin Dangoor <dan...@gmail.com> wrote:

Specifically, Modules 2.0 would acknowledge that some environments don't support the unwrapped format and specify that you must use the wrapped format if you want to support such environments (eg browsers).


Thanks for that, Kevin  -- you nailed it.

I have no intention of dropping /1.1 support, but I am certainly going to support /2.0 if it looks like I think it will.

Bumping the major rev to /2.0 also lets us a fix some other spec bugs, which might also help adoption.  Ironically, having the wrapper makes it easy for 1.1 platforms to run 2.0 modules. For example, global-require /1.1 implementations could pass a lambda-require into the module factory function when module.declare is invoked.

Wes

Wes Garland

unread,
Oct 22, 2010, 10:50:17 AM10/22/10
to comm...@googlegroups.com
On Fri, Oct 22, 2010 at 9:46 AM, Stefaan <stefaan.c...@advalvas.be> wrote:
sorry to come back on this but I still don't understand why such a
'module.declare'-wrapper cannot be optional.


If it is missing, then the module does not run everywhere.

If your module does not run everywhere, then you are not targetting CommonJS.

It's okay, BTW, to not target CommonJS when writing local code!  For example, I use many GCC-specific extensions in my daily work, however, when I contribute to projects which must run on Windows, I stick to ANSI C.

See how that works?  Specs do control how you write local code. They control what code looks like when it is intended to be portable.

Wes

Wes Garland

unread,
Oct 22, 2010, 10:50:54 AM10/22/10
to comm...@googlegroups.com
On Fri, Oct 22, 2010 at 10:50 AM, Wes Garland <w...@page.ca> wrote:
See how that works?  Specs do control how you write local code. They control what code looks like when it is intended to be portable.

Er,

See how that works?  Specs do not control how you write local code. They control what code looks like when it is intended to be portable.

Wes

It is loading more messages.
0 new messages