Opened 9 years ago

Closed 8 years ago

Last modified 8 years ago

#11893 closed enhancement (duplicate)

enhance modules to work with an async loader

Reported by: Rawld Gill Owned by: Rawld Gill
Priority: high Milestone: 1.7
Component: Loader Version: 1.5
Keywords: Cc: Kris Zyp, ben hockey
Blocked By: Blocking:

Description

This is part 2 of the AMD refactor; part 1 is described in #11869.

Rework algorithms/design as required so that modules will function correctly in a fully asynchronous, AMD-compliant environment. This includes removing assumption of any globals (e.g., dojo).

Change History (14)

comment:1 Changed 9 years ago by Rawld Gill

(In [23068]) Revert savetextarea changes in AMD refactor in RichEdit? (they did not work); !strict, refs #11869 and #11893

comment:2 Changed 9 years ago by Rawld Gill

Check code stack for document,write as this will not work with an async loader (e.g., savetextarea machinery in dijit/_editor/RichEditer.js)

comment:3 Changed 9 years ago by Kris Zyp

Cc: Kris Zyp added

comment:4 Changed 9 years ago by ben hockey

Cc: ben hockey added

comment:5 Changed 9 years ago by Les

Why named modules are used throughout?

The anonymous format is more compact and it provides other benefits.

See this reply form jburke:

http://groups.google.com/group/requirejs/browse_thread/thread/7705de003d629252/6e1035f45cc121d4?lnk=gst&q=anonymous#6e1035f45cc121d4

I do think the anonymous syntax is a bit more portable/more robust to file system changes, so there is some benefit to using it. I expect for modules that are distributed for reuse (in source form, where there is one module per file) it will be common to use the anonymous variant of the syntax.

comment:6 Changed 9 years ago by Kris Zyp

@Les: Great question, and perhaps it should be discussed more. The primary reason that we are using identified modules is because we have always allowed users to load modules with plain script tags:

&lt;script src="dojo/dojo.js"></script> &lt;script src="dojo/date.js"></script>

If dojo/date was an anonymous module, it would be very difficult to determine it's identity since the module loader didn't create script tag, and we won't know which script called define(). RequireJS does not support anonymous modules from user script tags either. James has said that user script tags simply aren't a priority with RequireJS, but with Dojo, I don't think we can simply drop support for them at this point.

With the legacy sync loader, I believe it is actually quite feasible to support at least plain script tags, since we can usually identify the module id by simply finding the last script element returned from document.getElementsByTagName("script"). Things get much more complicated when we use an async module loader that is also injected script tags that are loaded asynchronously (define isn't necessarily called by the last script). Things are also complicated if user uses the defer/async attribute on script, as they are no longer executed in order. At best these is extremely complicated, at worst it is simply impossible (I am not sure which it is).

We could say that we only support script tags with the sync loader (not sure if we would support async/defer), since it is the only one that we have to truly maintain backwards compatibility with. The async loader doesn't have any back-compat to worry about, so we could drop user provided script tag support, although I think we still consider to be very desirable functionality to support. We could also do more investigation into whether it is possible to identify anonymous modules loaded from user provided script tags, and how much code/overhead would be required to do this.

comment:7 Changed 9 years ago by Kris Zyp

Another issue that should be addressed: one should be able to depend on/require a module like "dijit/Tree" from a module loader like RequireJS, and all the necessary dependencies including Dojo itself should get loaded. We are currently very close on this, as our dependency set would include "dojo". We do slightly miss the mark though, because "dojo" isn't module that actually needs to be loaded, but rather "dojo/dojo". A few possible solutions:

  • Use "dojo/dojo" (and "dijit/_base") rather than "dojo" (and "dijit") to reference to the Dojo library and the Dojo namespace in all of the Dojo and Dijit code.
  • Include a dojo.js and dijit.js in the base directory of our distributions that would essentially just be something like:

define("dojo", dojo/dojo?, function(dojo){

return dojo;

});

We could also make sure that the package manager supports package.json instructions that would allow one to install Dojo such that this is handled properly for command line installation of a package (automatic creation of the base level dojo.js).

Arguably we could also use this as a transition forward, where dojo.js eventually becomes the backdraft async loader and dojo/dojo.js is the legacy sync loader (because a root dojo.js has never existed before).

  • Leave Dojo alone, but include directions for setting up Dojo as a package in RequireJS that explicitly specifies the base/main js file (so "dojo" points to "dojo/dojo" (I think something like this is possible with RequireJS's package support).

comment:8 in reply to:  7 Changed 9 years ago by Rawld Gill

Replying to kzyp:

Another issue that should be addressed: one should be able to depend on/require a module like "dijit/Tree" from a module loader like RequireJS, and all the necessary dependencies including Dojo itself should get loaded. We are currently very close on this, as our dependency set would include "dojo". We do slightly miss the mark though, because "dojo" isn't module that actually needs to be loaded, but rather "dojo/dojo".

[snip]

Agreed. In fact, I believe the v1.x design causes this problem to be unsolvable without employing one or more kludges:

  1. dojo.js is a sibling of all dojo modules (e.g., dojo is a sibling of dojo/back). The same goes for dijit.
  2. dojo.js conflates the loader and the dojo module.
  3. The modules in dojo/_base, as currently expressed (v1.5), depend on dojo yet dojo depends on them (they form a circular dependency).

These problems should be solved cleanly for the 2.x tree and a backcompat layer installed for the 1.x tree. Since dojo is just a package in 2.x, the solution ought to look something like this:

  1. The base modules (lang, array, et al) do not depend on dojo. They may depend on each other.
  2. main.js. which loads dojo, loads the appropriate base modules that are required to define the dojo module.
  3. There is a different main.js for different environments (rhino vs browser, etc.). These modules are trivial to construct so users can make different decisions (in other words, _base.js is not such a mystery).
  4. To make v2.x dead simple to use for novices, we include a loader named "dojo.js". For example, to include dojo and run myModule.js:
    <script data-main="myModule", src="dojo.js"></script>
    
  5. Once one or more of the new base modules are up, we can reference them (instead of the v1.x versions by modifying v1.x _base.js.

The design elements [1] and [2] have been prototyped in dojo-sie and pulsar.

comment:9 Changed 9 years ago by Kris Zyp

Are you saying that none of my proposed solutions would fix the problem? I am not sure I understand.

comment:10 in reply to:  7 Changed 9 years ago by Rawld Gill

Replying to kzyp:

Another issue that should be addressed: one should be able to depend on/require a module like "dijit/Tree" from a module loader like RequireJS, and all the necessary dependencies including Dojo itself should get loaded. We are currently very close on this, as our dependency set would include "dojo". We do slightly miss the mark though, because "dojo" isn't module that actually needs to be loaded, but rather "dojo/dojo". A few possible solutions:

  • Use "dojo/dojo" (and "dijit/_base") rather than "dojo" (and "dijit") to reference to the Dojo library and the Dojo namespace in all of the Dojo and Dijit code.

Yes, this will work. It is exactly what has been in dojo-sie from the start. The only different is that I used the name dojo/kernel.

  • Include a dojo.js and dijit.js in the base directory of our distributions that would essentially just be something like:

define("dojo", dojo/dojo?, function(dojo){

return dojo;

});

Hmmm, and how does dojo/dojo get filled up?

I'm currently refactoring dojo-sie to look like a package and--hopefully--the new v2.x layout. It's not quite done, but nearly so. To see the implementation of your idea here, take a look at: http://dojo-sie.altoviso.com/artifact?name=73f4b7466d10be9831c192b13f826862d12d8409

We could also make sure that the package manager supports package.json instructions that would allow one to install Dojo such that this is handled properly for command line installation of a package (automatic creation of the base level dojo.js).

Arguably we could also use this as a transition forward, where dojo.js eventually becomes the backdraft async loader and dojo/dojo.js is the legacy sync loader (because a root dojo.js has never existed before).

  • Leave Dojo alone, but include directions for setting up Dojo as a package in RequireJS that explicitly specifies the base/main js file (so "dojo" points to "dojo/dojo" (I think something like this is possible with RequireJS's package support).

It seems to me a key goal is to make dojo v2.0 look like a 100% standard package with no special tricks. Agree?

comment:11 Changed 9 years ago by Rawld Gill

Status: newassigned

comment:12 Changed 9 years ago by Kenneth G. Franqueiro

[23633] refs this ticket. (Check-in message passed under Trac's radar for this one)

comment:13 Changed 8 years ago by Rawld Gill

Resolution: duplicate
Status: assignedclosed

Look to #12672 for resolution of this ticket

comment:14 Changed 8 years ago by bill

Component: GeneralLoader
Note: See TracTickets for help on using tickets.