Skip to content

Loading…

Chaplin + Rails asset pipeline #212

Closed
starkovv opened this Issue · 29 comments

9 participants

@starkovv

Would be awesome to have an example of using Chaplin with Rails asset pipeline and Requirejs.

@lukateake

Forgive me if I'm misinformed but doesn't Paul Miller's Ostio and Ostio-API provide this? I'm not a Rails guy.

@starkovv

No he didn't.

Ostio - is a repository which holds only pure coffee-script front-end app which is subject to be compiled by using build tool.
Ostio-API - is just a Rails app, there is nothing about coffee-script, javascript and backbone/chaplin especially.

@paulmillr
Chaplin – JavaScript Application Architecture Using Backbone.js member

Yep, ost.io does not use asset pipeline because I prefer to decouple frontend and backend. This gives the ability to work on both projects in parallel, like we’re doing today. And to keep repos clean and much more maintainable.

After all, ost.io is just an example provider for ost.io api. Which means companies can do the same, open-source their frontends (because the real value is in the backend + data, in the most cases) and show developers that do stuff for their platform how to properly implement things. This will lead to massive API utilization etc.

A perfect example of this is Cloud.app for OS X. They gave away annotated source for their service which served as a great example backbone app.

@starkovv

Paul, I totally agree with you and I think the same way.

To be honest I use Rails asset pipeline because of its scss+compass functionality, especially about building image-sprites.

Nevertheless I'm still encouraging someone to show working example with rails asset pipeline and requirejs :-)

@paulmillr paulmillr referenced this issue in brunch/brunch
Closed

Add image sprites building plugin #418

@paulmillr
Chaplin – JavaScript Application Architecture Using Backbone.js member

building image-sprites

Sounds like a neat feature request.

I think you can use scss + compass with brunch too. Or maybe there is something shitty in brunch that prevents normal development with the stuff?

@starkovv

Probably the problem is that I'm not yet familiar with brunch.

@molily
Chaplin – JavaScript Application Architecture Using Backbone.js member

I’m going to create a repository for a quickstart with Rails, probably tomorrow. The basic idea is using the requirejs-rails gem.

@ktmiller
@molily
Chaplin – JavaScript Application Architecture Using Backbone.js member

@ktmiller That’s totally fine I think, we’re doing that, too.
Per default, the Rails asset pipeline only precompiles the files which are linked explicitly (i.e. processes and copies them to /public/assets). Some optional controllers and their dependencies will be missing and Chaplin won’t be able to lazy-load them.
One way to circumvent this is to load these dependencies explicitly in the main application module. Then requirejs-rails will compile them into the application.js. If you want to keep this file small and use the benefits of lazy-loading, you can add the individual files to config.assets.precompile so they are precompiled.

@paulmillr
Chaplin – JavaScript Application Architecture Using Backbone.js member
@paulmillr paulmillr closed this
@starkovv

Thank you for your efforts!

@ThomasConner

I am curious if anyone else might be able to think of a solution as I have not.

In rails when you are about to deploy you typically precompile your assets (js, css, etc.) into minified, gzipped single files (could be multiple but different topic). However, this works for chaplinjs up until you load a controller that is matched by a route. This will result in the following being called in the dispatcher class...

# Load the constructor for a given controller name.
# The default implementation uses require() from a AMD module loader
# like RequireJS to fetch the constructor.
loadController: (controllerName, handler) ->
    controllerFileName = utils.underscorize(controllerName) + @settings.controllerSuffix
    path = @settings.controllerPath + controllerFileName
    if define?.amd
        require [path], handler
    else
        handler require path

This loads the unminified version from the asset pipeline.

My question is if there is a way to load the minified version rather then the unminified version. Hope I was clear enough and this makes sense.

@molily
Chaplin – JavaScript Application Architecture Using Backbone.js member

@ThomasConner, if you add the controller file to config.assets.precompile, Rails will minify the file and copy it to the assets folder (http://guides.rubyonrails.org/asset_pipeline.html#javascript-compression). But this will just minify one file, one would need to use Dir.glob or similar to precompile all necessary files.

A better way is to set up a requirejs-rails configuration for each controller, so a package with all dependencies is created (not just the controller but also models and views).

If you don’t want lazy-loading at all but just one big file, it’s possible to force including all controllers and their dependencies into the application.js. https://github.com/chaplinjs/chaplin-rails demonstrates this by requiring all controllers in Application.

@ThomasConner

Thanks! I will give this a try.

@aaronchi

I built a simple compiler in rake that allows you to use Chaplin in the rails asset pipeline without any special extensions (commonjs/requirejs). If anyone is interested, I can put up a chaplin-rails gem.

@ThomasConner

I am very interested in this and wouldn't mind a gem. This sounds awesome!

@aaronchi

@ThomasConner Here's how I solved the loadController issue:

_(Chaplin.Dispatcher.prototype).extend
  loadController: (controllerName, handler) ->
    fileName = Chaplin.utils.underscorize(controllerName) +
      @settings.controllerSuffix
    moduleName = fileName.replace /(?:^|[-_])(\w)/g, (_, c) ->
      if c then c.toUpperCase() else ''
    handler window[Backbone.history.options.app][moduleName]

I camelize the underscored name of the controller and then search for it in the namespace that I have given to all of the classes in my chaplin app. The only thing you have to do is pass Chaplin the name of your application somewhere. I am doing this through the router:

@initRouter Newton.routes, app: 'Newton'

I'll put a gem together sometime next week with the compiler and post the link here.

@ThomasConner

Ok cool. Thanks

@molily
Chaplin – JavaScript Application Architecture Using Backbone.js member

@aaronchi What’s the benefit of putting all modules in a global namespace? The whole idea of AMD is to overcome this practice. Are you probably looking for almond.js, which is a minimal AMD implementation without any loading capabilities?

@aaronchi

@molily The AMD format can be a bit frustrating for Rails users as Rails has its own way of managing assets. Using AMD inside of the Rails asset pipeline requires special gems, and when used in conjunction with other javascript, it can be a pain to setup, and the advantages are limited IMO.

My compiler allows us to use Chaplin inside of Rails, without having to worry about AMD loaders or having to specify dependencies at the top of each class. In the end, it's just a different way of compiling the source code.

You already provide a commonjs/requirejs option. This would be a non-amd option that is targeted for use specifically in the Rails asset pipeline.

@vendethiel

Using AMD
i
s
a pain

Just joking, don't hit me, thanks for your work :p.

@molily
Chaplin – JavaScript Application Architecture Using Backbone.js member

Rails has its own way of managing assets

Unfortunately yes. It’s not an interoperable way to specify modules and dependencies in JavaScript, so it has no general value. I’m using Rails a lot but I try to avoid that. I agree that requirejs-rails, r.js and require.js/almond.js aren’t easy to set up, but it’s really worth the time to set up a build/packaging tool and a module loader that actually understands your JavaScript code and its dependencies.

Anyway, if you’re working on a way to translate the CJS require statements into asset pipeline requires, I think this will be useful for several people.

… without having to worry about AMD loaders or having to specify dependencies at the top of each class.

O RLY? Specifying module dependencies (or, if possible, use dependency injection) is a crucial feature of software systems. That’s why Chaplin is using AMD/CJS after all.

@starkovv

@molily @aaronchi After all, I agree with @paulmillr that it's not good idea to build backend and frontend in the same environment. As I think the best way in current context would be to use Rails explicitly for backend and Brunch (http://brunch.io) for frontend.

@chrisabrams

@starkovv Please convince some of the engineers at my office that it is better to split the environment :P

@starkovv

@chrisabrams these are actually two different apps:
1) backend API
2) fronend web-application / iOS application / other

I'd compare it with salad of vegetables and fruits. Not tasty, at least for me :P

@chrisabrams

Right, same here. We have a web app, iOS app, and Android app. Still they'd rather not split things up, even if that means repeating theirself :O

Doesn't make any sense to me...but at least it's not my team.

@aaronchi

This is not intended to be a discussion about the 'best' way to setup an application. Some people want an option to use Chaplin in Rails so let's give them the option.

Backbone works fine without AMD. The Chaplin maintainers want to enforce AMD, and that's fine too. But it is still a useful platform that works fine when you compile it without the AMD structure.

@starkovv

As I think the more options is available the better for everyone. That's how open-source rocks.

@paulmillr
Chaplin – JavaScript Application Architecture Using Backbone.js member

The Chaplin maintainers want to enforce AMD

Actually I don’t like AMD. You still can use chaplin without AMD, with Brunch, which uses synchronous common.js modules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.