Requirejs to Curl migration

135 views
Skip to first unread message

Mike Macaulay

unread,
Oct 3, 2013, 10:01:38 AM10/3/13
to cuj...@googlegroups.com
Hey all,

Has anyone tried to migrate a requirejs project to curl/cram?  I include cram because we currently use r.js to concatenate our project for production.  I'm considering it for our rather large project and would like to know if there are any pitfalls out there I should know about.  The configs look similar, would it be as simple as converting "require" calls to "curl" and tweaking my requirejs config to be a curl one?  I know it's not 1.0 yet so should I wait?  

Mike

unscriptable

unread,
Oct 3, 2013, 12:26:49 PM10/3/13
to cuj...@googlegroups.com
Hey Mike,

The configs are very similar, but there are a few differences.  For instance, if you are using legacy (non-module) javascript, the config is different.  We use curl's legacy loader config[1], rather than requirejs's shim config.  Also, cram's concepts are a bit different than r.js.  Hopefully, you'll find cram simpler to master. :)

I know it's possible to convert since others have done it. And it shouldn't be too much work since your application code shouldn't change unless you're using lots of third-party AMD plugins in your modules.  

Hm, I guess the i18n plugin works a bit differently, too.  Are you using requirejs's i18n plugin?

We'll be glad to help, regardless.

Mike Macaulay

unread,
Oct 3, 2013, 12:42:11 PM10/3/13
to cuj...@googlegroups.com
No, the only plugins we're using are text ATM, which looks trivial.  

We do use a lot of non-AMD third party modules (Backbone for example).  I'll check out the legacy loader.  Thanks for the quick response!  

Mike

Mike Macaulay

unread,
Oct 5, 2013, 1:42:38 AM10/5/13
to cuj...@googlegroups.com
Hey John,

So I took a stab at converting from requirejs, and I think I may be thinking incorrectly about what curl could provide me, especially with the legacy loader.  So, our basic app is a Marionette app (built on backbone), and we have some jquery plugins we use, my config file currently looks like this:

    (function (curl) {

    var config = {
        paths: {
            jquery: 'assets/js/components/jquery/jquery',
            curl : 'assets/js/components/curl/src/curl',
            gritter : {
                location : 'assets/js/components/gritter/js/jquery.gritter.js',
                config : {
                    loader : 'curl/loader/legacy',
                    factory : function(){
                        return $.fn.gritter
                    },
                    requires: ['jquery']
                }
            },
            icanhaz : {
                location : 'assets/js/libs/icanhaz',

                config : {
                    loader : 'curl/loader/legacy',
                    exports : 'ich'
                }
            },
            templates : 'assets/templates',
            bootstrap : 'assets/js/components/bootstrap/docs/assets/js/bootstrap'
        },
        packages: [
            { name: 'backbone', location : 'assets/js/components/backbone', main:'backbone.js'},
            { name: 'lodash', location: 'assets/js/components/lodash/dist', main: 'lodash.js'},
            { name: 'underscore', location: 'assets/js/components/lodash/dist', main: 'lodash.js'},
            { name: 'marionette', location: 'assets/js/components/marionette/lib/core/amd', main:'backbone.marionette.js'},
            { name: 'backbone.wreqr', location : 'assets/js/components/backbone.wreqr/lib/amd', main:'backbone.wreqr.js'},
            { name: 'backbone.babysitter', location : 'assets/js/components/backbone.babysitter/lib/amd', main : 'backbone.babysitter.js'},
            { name: 'wire', location: 'assets/js/components/wire', main: 'wire' },
            { name: 'when', location: 'assets/js/components/when', main: 'when' },
            { name: 'meld', location: 'assets/js/components/meld', main: 'meld' },
            { name: 'cola', location: 'assets/js/components/cola', main: 'cola' },
            { name: 'poly', location: 'assets/js/components/poly', main: 'poly' }
        ]
        ,preloads: [
            'jquery',
            'icanhaz',
            'gritter'
//            ,'curl/debug'
        ]

    };
    curl(config, [
        'jquery'
        ,'icanhaz'
        ,'gritter'
        ,'app/application'
    ], function(jquery, ich,gritter, application){
        console.log('gritter:  ', jquery.gritter);    // prints out just fine
        console.log('required gritter: ', gritter);   // prints out undefined
        console.log('application:  ', application);   // prints out application object

    }).then(notify, fail);

    function notify() {
        console.log('loaded');
    }

    function fail(ex) {
        console.log('An error occurred while loading.', ex.message);
        if (ex.stack) console.log(ex.stack);
    };
})(curl);


To get this to work, I was able to use amdjs/backbone, and use the "trick" to have it think lodash was underscore.  Marionette was more difficult because the "amd" bundles don't include its dependencies (wreqr and babysitter), so I had to manually add them in there, ultimately while weird, I can live with it.  My question comes to the two non-AMD modules, 'gritter' and 'icanhz'.  

My application builds modules as AMD, and in requirejs land, it would look like this: 
// #Main Application
define(function(require) {
   'use strict';
    // Load attached libs and application modules
    var $ = require('jquery'),  
        _ = require('lodash'),
        Backbone = require('backbone'),
        ich = require('icanhaz'),  // error comes from here
        Notify = require('./services/notify');


    // Setup templates
    ich.addTemplate('main', require('text!templates/main.html'));
... rest of module



In requirejs, I would configure them with a path, and then be able to 'require' them in my other modules.  Requirejs would then return me the object (ich in this case) and I would go my merry way.  But with Curl, this doesn't work.  Instead I get an error saying Uncaught Error: Module not resolved: icanhaz. So, my question is, why can I curl this non-AMD module just fine but can't require it?  It now seems like if I want to use icanhaz, I need to use the global, but that can't be right. :)  Is the solution that I need to inject it in my module as a dependency from curl using something like wire?  Or am I just doing everything wrong? :)  Is there a better way?  

Thanks in advance for your help!

Mike

unscriptable

unread,
Oct 7, 2013, 4:07:11 PM10/7/13
to cuj...@googlegroups.com
Hey Mike,

> Marionette was more difficult because the "amd" bundles don't include its dependencies (wreqr and babysitter), so I had to manually add them in there

This is making me sad.  Unfortunately, somebody doesn't understand that wrapping global legacy code in AMD typically doesn't fix anything.  

> So, my question is, why can I curl this non-AMD module just fine but can't require it?

You should be able to.  I don't think we have a test that uses a local/scoped require on something that has been loaded via the legacy loader.  Time to create one, if so.

Some other interesting things I saw in your code snippet:

1. You should remove the ".js" extensions from the `main` properties in the packages.  curl is forgiving of those, but they're strictly incorrect since `main` is supposed to be a module id.
2. Did you try running this code without the preloads?  Those shouldn't be necessary (iiuc).
3. The amdjs/backbone project is chronically out of date.  You could use the legacy loader (or the cjsm11 loader) with the official backbone.js instead if you like.  Note: when using the cjsm11 loader for backbone, you have to do this somewhere because of a backbone.js bug: `window.Backbone.$ = window.jQuery`.  

-- John

Mike Macaulay

unread,
Oct 7, 2013, 8:00:45 PM10/7/13
to cuj...@googlegroups.com
Hey John,

I added a test to the suite to demonstrate the problem, https://github.com/cujojs/curl/pull/233.  This is actually my first time doing something like this, so please forgive me if i'm doing something wrong process-wise. :)  I'd love to try to fix it myself, and will try if i have time, but at least its in your code base now.  

Yes, I agree on the Marionette problem, its almost not even worth trying to do AMD for it.  As for amd-backbone, it looks like they've caught up.  They're on 1.0.0, which is the latest base version, and I didn't have to do the bug workaround you mentioned (yay!)  

Mike

unscriptable

unread,
Oct 7, 2013, 8:15:44 PM10/7/13
to cuj...@googlegroups.com


On Monday, October 7, 2013 8:00:45 PM UTC-4, Mike Macaulay wrote:
Hey John,

I added a test to the suite to demonstrate the problem, https://github.com/cujojs/curl/pull/233.  

Woot! Thanks Mike!  I'll take a look asap.

 
This is actually my first time doing something like this, so please forgive me if i'm doing something wrong process-wise. :)  I'd love to try to fix it myself, and will try if i have time, but at least its in your code base now.  

Yes, I agree on the Marionette problem, its almost not even worth trying to do AMD for it.  As for amd-backbone, it looks like they've caught up.  They're on 1.0.0, which is the latest base version, and I didn't have to do the bug workaround you mentioned (yay!)  

The work-around is only needed when using backbone as a CommonJS module, not an AMD module, afaik.

-- J

Mike Macaulay

unread,
Oct 14, 2013, 5:47:52 PM10/14/13
to cuj...@googlegroups.com
Hey John,

Got a chance to try out the fix you made on the dev branch and it looks good!  I've now got my app up and running (yay!).  The next step is to set up cram to bundle my app.  Using the config i threw out above, but with your changes, I'm having some trouble.  It doesn't seem like cram is reading the curl config for the non-amd module 'icanhaz' correctly.  When i run cram i get this 

node ../node_modules/cram/cram.js index.html
Parsing index.html for curl configuration
Found data-curl-run: config.js
warning: grokking "index.html": Did not inspect code inside `curl()` callback(s).
warning: grokking "index.html": Did not inspect code inside `.then()` callback(s).
`appRoot` resolved to .
`baseUrl` resolved to somedir/client/
`output` resolved to config.cram.js
Compiling modules
cram failed:  ENOENT, open '/fullPath/client/icanhaz.js' icanhaz app/application
Error: ENOENT, open 'fullPath/client/icanhaz.js' icanhaz app/application

index.html is using this form: 
 <script src="assets/js/components/curl/src/curl.js"></script>
    <script data-curl-run src="config.js"></script>
(to save space i won't paste the config here again)
To me, it doesn't seem like cram is reading the paths option in the curl config that tells it 'icanhz' is a legacy loaded module.  So my question is, am I doing something wrong?  As always, any help would be greatly appreciated!

Mike

unscriptable

unread,
Oct 16, 2013, 8:33:24 AM10/16/13
to cuj...@googlegroups.com
Hey Mike,

The config looks good.  Here are the parts of cram's output that I'm suspicious of:

`appRoot` resolved to .
`baseUrl` resolved to somedir/client/
...
cram failed:  ENOENT, open '/fullPath/client/icanhaz.js'

The code that runs when appRoot != baseUrl is poorly tested.  So I'm suspicious of that. 

Also, the leading slash in '/fullPath/client/icanhaz.js' makes me suspicious.  Is it really looking at the root of your file system?

Any ideas how we could isolate these things in your setup?

-- John
Reply all
Reply to author
Forward
0 new messages