Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

the amd question #20

Closed
sheppard opened this issue Jun 21, 2013 · 7 comments
Closed

the amd question #20

sheppard opened this issue Jun 21, 2013 · 7 comments

Comments

@sheppard
Copy link
Contributor

Thanks for getting this started, it will be great to bring Proj4 up to speed with the modern web. My biggest interest in this process is in adding AMD support to Proj4js. I'm assuming everyone is familiar with AMD already, and perhaps already have opinions for or against it (if not, please do take a look at the RequireJS intro).

In the absence of "real" modules for the web, AMD is becoming more and more common as a way to support modular JavaScript library development (jQuery Mobile and Dojo being prominent examples). Thus, I'd argue that the question here is not whether or not to support AMD, but whether or not to integrate it directly into the Proj4js build process. I could see two overall approaches:

  1. Use whatever module/build system you prefer (CommonJS, Closure, Smash...), but add the typical AMD boilerplate to the built file, so that it can be used by other projects as either a traditional "browser global" file as well or an AMD module. I'm hoping we can all agree this should be done regardless.
  2. Write all of proj4js' internal modules in the AMD format, and use r.js to build the resulting file, perhaps with the boilerplate in 1. I find this option particularly compelling as it would allow me to write my project-specific code with explicit dependencies on the specific submodules in Proj4js that I need - meaning I wouldn't need a separate Proj4js build, but would just compile it as part of my app build process. This is my preferred option, but I understand that it may be less valuable to others who aren't already using AMD.

FWIW, I'm currently building a JavaScript library I call wq.app that consists only of AMD modules - I don't even have a canonical "built" distribution and don't provide any browser global variables. To get this to work without "shims" I've started maintaining AMD-compliant versions of several popular JavaScript libraries as part of my repo.

What do you think?

@calvinmetcalf
Copy link
Member

So I've used browserfy/commonjs modules with great success (especially for making scripts that work in both the browser and node) but have no real experience with AMD. My gut would be to go to the browserfy route as it would allow better node.js interop/I understand it. Whichever way we go having a window global for the browser is mandatory, though you will notice that I managed to to do it in the current build of the script withough actually using the window object as I was planning, but haven't gotten around it, to stick a if(type module !== 'undefined'){module.exports=proj4;} in there somewhere

@calvinmetcalf
Copy link
Member

I may have read this article right before you opened this issue.

@ahocevar
Copy link
Member

Let me explain what my goals for the build are, and how these are a bit different than other build stories: The required files are determined by the proj definitions that a user wants to have supported. For a full build with all transforms, we currently have a simple list of files in the grunt config, which works fine. For a custom build with only the transforms needed for the projections the users is interested in, a preprocessing step would parse the proj defs of the projections the user wants and could then build the list of required files.

I think where AMD could come in is a barebone build where all transform functions would be lazily loaded, based on the defs that a user adds. Personally, this is no priority for me, but if somebody wants to implement that, I won't object unless it significantly increases the built library size for the custom and the full build.

I'm currently working on the custom build with the preprocessing. This will probably be interesting to look at before diving into AMD for proj4js.

@sheppard
Copy link
Contributor Author

@calvinmetcalf thanks for the link - the author raises some valid concerns, though I obviously don't agree with all of the conclusions. I'm planning to write up a full response, and can post a link here when I do. For the purposes of this discussion, I'd like to clarify that I'm proposing we use AMD as our module/dependency syntax primarily for interop. with other projects_, not necessarily because I want async loading per se (though it could be useful down the road_*). It's true that the async syntax in AMD is what differentiates it from CommonJS, and is necessary in order to make it possible to use modules directly within the browser. In practice, I was assuming users would normally be using a build process anyway.

@ahocevar, I agree that the goals for Proj4js build process do sound a little different than the typical workflow. However, I still think this could accomplished with a creative use of an existing module system. For example, I'd imagine a proj4js derivation of UTM15N could look something like this (using AMD for this example, though the same could be accomplished via CommonJS modules):

// utm15n.js (autogenerated... somehow)
define(['Proj', 'projDefs/utm'], function(Proj, utm) {
   return new Proj(utm, {'zone': 15});
});

// projDefs/utm.js
define(['./tmerc', '../common'], function(tmerc, common) {
  return {
    init : function() {
      ...
      this.long0 = ((6 * Math.abs(this.zone)) - 183) * common.D2R;
      ...
      tmerc.init.apply(this);
      this.forward = tmerc.forward;
      this.inverse = tmerc.inverse;
    }
  };
});

// projDefs/tmerc.js
define(['../common'], function(common) {
  return {
    init : ...,
    forward : ...,
    reverse : ...
  }
});

FWIW, it looks like tmerc already has a dependsOn attribute that was originally used for a similar purpose.

To make this work, the new Proj4js build process would still need to generate the equivalent of utm15n.js for each requested projection. However, once that was done, the underlying module system would be able to automatically inject the dependencies needed for the custom build. I think this would be less work overall than writing a custom dependency resolver, with the added benefits that come from using a standard(-ish) modularization/dependency syntax. However, I'd be interested in your thoughts.

Notes:

  • *jQuery, jQuery Mobile, Dojo, GeoMOOSE, and wq.app either have already, or are in the process of, converting to AMD as the project-internal module format.
  • **It turns out that AMD is directly compatible with any service that supports JSONP: you can simply request the callback to be define

@calvinmetcalf
Copy link
Member

this can be closed

@ahocevar
Copy link
Member

Agreed. Thanks @calvinmetcalf! @sheppard, please try out what was merged with #32 and create new issues if you encounter any problems.

@sheppard
Copy link
Contributor Author

Will do, thanks again @calvinmetcalf for working on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants