-
Notifications
You must be signed in to change notification settings - Fork 24
CommonJS proposal #298
Comments
+1 |
I'm interested and would like to see this solved eventually. I do like the stitch approach which this is similar too, but I know people are going to be upset that its not the same AMD standard or whatever. There isn't much of a standard for publishing these types of packages. And I don't want to introduce a new I'm tracking jquery's new plugin effort. I think it would be interesting to support their package.json standard and handle all the dependency resolving. Its still going to be a while before they shake things out. Is there anyway you can ship this as a plugin for the time being? Do you need any extra hooks? |
Sure thing, I'll implement it as a plugin for now :) |
@maccman I'm happy to see someone putting in the effort into this. Just know this won't get solved over night. You're going to need to have some patience with me since its not my top priority right now :) I will keep this issue open for future discussion. Note For anyone following along, any "+1"s aren't going to add any value to this discussion. I know people would like to see this. Please only comment if you have relavent details to add. |
+1, this is a cool idea. I generally agree with @josh -- it'll be a while before the dust settles, and would probably confuse folks if Sprockets included it, but a sprockets plugin that got interested folks started with CommonJS modules could only be a good thing. I'd be happy to contribute |
I've already started down this path with a Rails plugin, http://github.com/dkastner/nodeify I went with an existing project called browserify to do the require parsing. There are several advantages to doing this:
While working on this I decided that the sprockets The only downsides so far:
If any of this interests you at all, I'd love feedback/help! I wanted to throw this out there in case it could save you time. If you'd like an example of an app that I've started to port to nodeify, check out https://github.com/brighterplanet/hootroot1/blob/nodeify/app/assets/javascripts/application.js |
One more thing: another advantage of node/npm/browserify is that you can have a package.json in your project that acts similarly to a Gemfile, making JS package management just as easy as rubygems. |
@josh I've got a basic version working here: https://github.com/maccman/sprockets-commonjs It uses a library I've written called Holmes to find calls in 'require()' in the JavaScript AST. Unfortunately this library requires node - however I can't really see a way round this apart from parsing the AST in Ruby. https://github.com/maccman/holmes Anyway, have a few Sprockets questions:
Cheers, |
Statically parsing the AST is scary. Theres no way you can handle cases like I know your researching commonjs more for application purposes. I've mainly been thinking about the "package" usecase.
We could use a similar hack to backbones's package.json would specifiy it depends on jquery, so you can assume that require. However, these are simple single file cases. I dunno how you'd adapt node's runtime relative requires. I was thinking about all these stuff for stitch, but then node's package.json structure became less defined and they removed the idea of a load path. Which totally crushed my dreams. |
Thanks for starting the investigation. I'd love to see some sort of runtime module exposure in Sprockets. I think AST parsing is a non-starter. It immediately excludes a whole class of dynamic programming techniques like @josh mentioned above. These aren't just theoretical use cases either—we used them when we built Basecamp Mobile for things like automatically loading templates in a view class:
Maybe a simpler way to start with modules would be with a simple directive in each file:
This would automatically wrap the file in a closure in the asset bundle, keyed in an object by its logical path and exposed to a |
It's worth noting that Sprockets' JST support is already a sort of runtime module system. |
@sstephenson I agree that there are lots of issues with AST parsing, such as dynamic calls and requiring Node. At the moment, for dynamic calls, I'm issuing a Ruby warning. The thinking was that if you wanted to do dynamic requires, you should explicitly require all the files as well, either through I'm in two minds about AST parsing as well - but it seems a bit Janky to have to duplicate all requires (i.e. in the conditional comments, and using require()). I think this approach is a good compromise. The fact that it requires Node though, could be a deal breaker. Isn't having #= module support basically the same as having |
Yeah, a module directive is no better than an extension. My bad. I agree that duplicating requires is nasty in general. But it's less offensive when you think of it as bundle inclusion (require directive) vs. runtime module access. It gets simpler if we assume most people will want to pull in all modules into their bundles with one of the bulk-require directives like |
@maccman since you're the author of spine, I'm curious how you see that fitting into this system. |
Yes, I think you guys may be right. I'll remove the AST stuff. |
Yes, I guess Spine's |
(subscribe) |
Ok, it's done now - what do you think? |
Thanks @maccman, I will definitely put this on my list of things to test in my current Rails/Spine.JS application. |
@josh, @sstephenson what do you think of the proposal? Any reason this couldn't be included in core down the road? |
I just read this thread from top to bottom because I'm interested in solution that permits me to use common.js with rails. Way up at the top @dkastner offered an alternative solution that near as I can tell appears very viable and moves as close as possible to a pure javascript approach to handling javascript assets. However I didn't see any comment from anyone else regarding @dkastner's proposal. @josh @maccman @sstephenson Since you three seem to be most involved in the discussion and have deeply explored ruby-based, I'm especially curious to hear you views on @dkastner's approach, especially since at the end of the day both solutions require node.js anyways and it looks like his approach would allow us to avoid have to use both require() statements and sprockets directives. |
@malandrew afaik only parsing the AST requires Node - the other approach doesn't. Parsing the AST is really slow too. I'm quite happy doubling up require calls, as I find most of the time I'm using require_tree anyway. |
@maccman so when you removed AST parsing from sprockets-commonjs, you also ended up removing the node.js dependency from the lib? If so, does removing node.js as a dependency matter that much because AFAIK you still end up with v8 as a dependency via therubyracer in order to perform uglification/minification? When you use require_tree, do you basically use it for everything, but that final javascript onready/onload module that kicks off the execution of your single-page app, or are there other places where you explicitly link to a file. I might be naive here, but as the common.js approach wraps modules up using function declaration, it seems like file order doesn't really matter at all, does it? Any other views on @dkastner's approach versus yours. I'm looking at both and trying to figure out which one is best for our use. Are you already using sprockets-commonjs in production? |
@malandrew That's a good point. However, the uglify gem actually relies on execjs - which doesn't require v8 compilation (although still requires some sort of JS runtime). Due to the way Holmes is implemented, it specifically relies on Node (which breaks execjs somewhat). As for require_tree, I basically use it for everything (i.e. the app dir). That's correct, file order doesn't matter. The only other thing I'd say is that I've been down a number of paths trying to solve this issue - and imo the simplest solution is the best here. Yes, we're using sprockets-commonjs in production at Twitter. |
@maccman Awesome that you are already using it in production at Twitter. Looks like when I'm done building this prototype for a potential client, I'll go ahead and implement sprockets_commonjs in my startup's app. Personally, I'm still interested in a solution like @dkastner's because we're looking to move to node.js long term (at least for real-time and event-driven parts of our API) and I personally would like to work towards a complete decoupling of our client-side app and API backend. Moving to sprockets-commonjs and then to nodeify would give a path to a complete separation of concerns. So if I got this right, you no longer use Holmes in sprockets-commonjs, correct? Don't you think being able to leverage node and npm would be more valuable long-term for handling all javascript assets, or would that be out of line with there Rails is trying to position itself? It seems like an issue of where the complexity lies. The nodeify approach reduces complexity for those largely responsible for building the javascript front-end (the assumption here is that it is large, which is a reasonable assumption if commonjs is seen as warranted) at the cost of complexity for those managing the production environment. Does requiring node.js and npm add that much more complexity to the production environment? As someone who I believe is primarily a javascripter, I figured you'd favor an approach that leverages npm. |
Keep in mind, when considering the long-term usefulness of this, that ES.next will have its own module syntax which does not use CommonJS. Dave Herman says the plan is for Node to migrate to this new system once it is implemented in V8. |
@jimmycuadra True. The way I see it any step from sprockets directives towards common.js is already a step towards organizing your code in a way that switching to ES.next should be simpler if upgrading your node.js version in the future requires updating how you declare dependencies. I also reckon there will be ways to maintain backwards compatibility with commonJS for sometime afterwards as well.. Right now we're using namespacing in our app and it is painful. |
@maccman the speed penalty of walking the AST isn't really an issue if you precompile your assets for production. It just slows down your page loads in development. I've seen about 2s of initial load time on a fairly complex (w.r.t. module require depth) site (http://hootroot.com, http://github.com/brighterplanet/hootroot1) on my old white MacBook. |
Still a cool idea, but I think its going to continue to live as a plugin for now. |
Just wanted to check, if there are any new thoughts in the meanwhile about integrating CommonJS with Sprockets. I looked into https://github.com/maccman/stylo/blob/master/assets/javascripts/application.js , and it looks to nicely isolate components. |
I think it would be awesome if Sprockets supported CommonJS, and I think you could implement it in a backwards compatible approach.
I've been spiking CommonJS support for Sprockets in a branch:
maccman@9e0e82d
For developers, the end result is:
There's a number of issues with my initial approach - such as not parsing out requires, having no dependency tree etc. I'm planning on resolving all this on the weekend.
However, my question is - if I did this work, is it likely to get accepted?
The text was updated successfully, but these errors were encountered: