0

I am using Almond and the r.js optimizer to combine all my scripts in a single file for a Backbone.js-based Single Page Application.

My build file:

({
    name: '../bower_components/almond/almond',
    include: ['main'],
    insertRequire: ['main'],
    baseUrl: 'src',
    optimize: 'uglify2',
    mainConfigFile: 'src/main.js',
    out: 'javascripts/scripts.js',
    preserveLicenseComments: false,
    paths: {
        jquery: '../bower_components/jquery/dist/jquery',
        underscore: '../bower_components/underscore/underscore',
        backbone: '../bower_components/backbone/backbone',
        kineticjs: '../bower_components/kineticjs/kineticjs',
        'jquery-ui': '../bower_components/jquery-ui/ui',
        'jquery.layout': '../bower_components/jquery.layout/dist/jquery.layout-latest'
    },
    shim: {
        'jquery.layout': {
            deps: [
                'jquery-ui/core',
                'jquery-ui/draggable',
                'jquery-ui/effect',
                'jquery-ui/effect-slide'
            ],
            exports: 'jQuery.fn.layout'
        }
    }
})

In my Backbone view I initialize the jquery-layout plugin:

define(['backbone', 'underscore', 'jquery.layout'], function(Backbone, _) {
 'use strict'

    return Backbone.View.extend({
        el: $('#application'),

        initialize: function() {
            this.$el.layout({
              west: {
                size: '50%',
                closable: false,
                slidable: false,
                resizable: true
              }
            });
        }
    });
});

The panes show up correctly, however I cannot resize any of them. I found that $.fn.draggable (JQuery UI Draggable widget) is not being initialized at the time when the jquery-layout plugin is declared.

This indicates that probably the widget is not being loaded. So I checked the combined source file and noticed that the JQuery UI Draggable widget code appears before the jquery-layout plugin code, which means the dependencies are inserted in the correct order. Printing $.fn.draggable in the Firebug console also shows that the widget is available, at least after the document is ready.

jQuery, underscore, backbone, jQuery UI are all AMD modules. jquery-layout has no AMD compatibility, hence the shim config. It depends on JQuery UI's ui.core and ui.draggable per their docs.

For all of this to not sound too abstract, here is a demo of the jquery-layout plugin.

I have "wasted" over 8 hours trying to figure this out in vain, any help on how to fix this would save my day. Most probably this would involve only some fix of my shim config in the build file.

Genti Saliu
  • 2,643
  • 4
  • 23
  • 43

2 Answers2

1

I solved the problem by making the non AMD-aware jquery-layout plugin AMD-compatible. I used the onBuildWrite hook of the r.js optimizer in the build file. This way the jQuery UI dependency ui.draggable is initialized before the code of the non AMD-aware plugin loads:

({
 name: '../bower_components/almond/almond',
        include: ['main'],
        insertRequire: ['main'],
 baseUrl: 'src',
 optimize: 'uglify2',
 mainConfigFile: 'src/main.js',
 out: 'javascripts/scripts.js',
 preserveLicenseComments: false,
 paths: {
  jquery: '../bower_components/jquery/dist/jquery',
  underscore: '../bower_components/underscore/underscore',
  backbone: '../bower_components/backbone/backbone',
  kineticjs: '../bower_components/kineticjs/kineticjs',
  'jquery-ui': '../bower_components/jquery-ui/ui',
  'jquery.layout': '../bower_components/jquery.layout/dist/jquery.layout-latest'
 },
 shim: {
  'jquery.layout': {
   deps: ['jquery', 'jquery-ui/draggable', 'jquery-ui/effect', 'jquery-ui/effect-slide'],
   exports: 'jQuery.fn.layout'
  }
 },
 onBuildWrite: function(moduleName, path, contents) {
  if (moduleName == 'jquery.layout') {
   contents = "define('jquery.layout', ['jquery', 'jquery-ui/draggable', 'jquery-ui/effect', 'jquery-ui/effect-slide'], function(jQuery) {" + contents + "});";
  }
  return contents;
 }
})
Genti Saliu
  • 2,643
  • 4
  • 23
  • 43
  • "This way the jQuery UI dependency ui.draggable is initialized before the code of the non AMD-aware plugin loads" Well, that's exactly what your `shim` configuration in your question *should* be doing. With the information you provide in the question and in the answer, there's nothing that indicates why `shim` should not give you the results you wanted. (You do have that `shim` in your runtime configuration *too*, right?) – Louis Mar 19 '15 at 16:23
  • The shim specifies the dependencies and the order in which they are included in the final script. This always worked. The non-AMD aware plugin references `$.fn.draggable` during parse time (see line 302 in its source code: https://github.com/allpro/layout/blob/master/source/stable/jquery.layout.js#L302), at which time `$.fn.draggable` is not available, because the jQuery UI plugin hasn't been initialized yet. What is a "runtime configuration"? I combine the files in a large script and just use that script, even in development. Gulp watch runs r.js optimizer when I modify JS files. – Genti Saliu Mar 19 '15 at 16:46
0

Following the answer from @Genti and using latest jquery-ui, following shim worked for me.

  shim: {
    'jquery.layout': {
      deps: ['jquery', 'jquery-ui/core', 'jquery-ui/widgets/draggable', 'jquery-ui/effect', 'jquery-ui/effects/effect-slide', 'jquery-ui/effects/effect-drop', 'jquery-ui/effects/effect-scale'],
      exports: 'jQuery.fn.layout'
    }
  }
django
  • 2,809
  • 5
  • 47
  • 80