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
--
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.
Fabian
Goal:
A module source format that works natively on the server and browser *and supports necessary browser loading intricacies*.
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.
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
+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
+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.
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>
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
+1.
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
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
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
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 asNo, I think it should be clear that this specification does not impose
> functions.
any requirements on existing CommonJS/Modules loaders.
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
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
On 10-10-20 12:54 PM, Wes Garland wrote:Right. That is the whole point.
It also appears to be put forth as another idiom in which to author
CommonJS.
+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
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
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.
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
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
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.
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.
very interested in this - can somebody give me a pointer where I could
find some info on this module./require.resource?
what if the developer would package his code in a require.ensure to
declare the dependencies?
require.dependencies(['x'], function () {
var x = require('x');
});
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
>
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 agreementThis 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
--
Wesley W. Garland
Director, Product Development
PageMail, Inc.
+1 613 542 2787 x 102
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
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.
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
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
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
Who is Chris? ;)
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:which seems to not exhibit the securability problem?
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
- 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.)
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
I do think we need to vote on an alternative source format that can be transformed into an acceptable transport format.
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
*** 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 :-) ).
On 10-10-21 2:29 PM, Dean Landolt wrote: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 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.
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.
Which one do you author in? No heuristics can really answer that
question (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.
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.
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
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
Can we state that a 2.0 compliant loader must also support 1.1?
+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
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
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.
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.
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
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
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
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.
Q2: Is having a "module" global variable for your system technically
infeasible?
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
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/
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.
So I believe it passes the spirit of those two tests -- error when a
dependency is not available.
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
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.
Specifying an array of dependencies before the function implies the
discussion around injection.
The above form should come with a note about it being a problem for
some envs without a usable Function.prototype.toString,
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.
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).
sorry to come back on this but I still don't understand why such a
'module.declare'-wrapper cannot be optional.
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.