metafizzy / isotope-packery

packery layout mode for Isotope
42 stars 15 forks source link

isotope + packery-mode + define + require.js #12

Closed momolog closed 9 years ago

momolog commented 9 years ago

This is very similar to #8 but the solution given there will not work, so I felt I should open another ticket.

This is my setup: I intend to use Isotope in a library defined in mylib.js. This lib is required in index.js, which in turn gets loaded from index.html like so:

...
<script data-main="index" src="/js/require.js"></script>
...

This is index.js:

require(['/js/mylib.js'], function(mylib){
  mylib.myfunction();
});

This was my mylib.js:

require.config({
  paths: {
    'jquery':         '/js/jquery-1.11.2.min',
    'isotope':        '/js/isotope.pkgd.min',
    'imagesloaded':   '/js/imagesloaded.pkgd.min',
    'packery-mode':   '/js/packery-mode.pkgd'
  },
});

define(['jquery', 'isotope', 'imagesloaded', 'packery-mode'], function(jquery, Isotope, imagesLoaded, packeryMode){
  var mylib = {
    myfunction: function(){ alert('works!'); }
  };
  return mylib;
});

Now this will give Script error for: isotope/js/layout-mode for the reasons given in #8. Redefining this like proposed in #8 :

require.config({
  paths: {
    'jquery':         '/js/jquery-1.11.2.min',
    'isotope':        '/js/isotope.pkgd.min',
    'imagesloaded':   '/js/imagesloaded.pkgd.min'
  },
});

define(['jquery', 'isotope', 'imagesloaded'], function(jquery, Isotope, imagesLoaded){
  require( 'packery-mode', function(packeryMode){
    var mylib = {
      myfunction: function(){ alert('works!'); }
    };
    return mylib;
  });
});

does break the define, because now mylib will not be returned anymore.

This means, I am either left with the script error or without the possibility to define a module using Isotope with require.js.

desandro commented 9 years ago

Thanks for reporting this issue. Here's what I've found to work. The issue is that we need a second require call within define. Because require is async, we need to use a callback so that the lib from mylib can be completed before we use it.

index.js

requirejs( [ './mylib.js'], function( loader )  {
  // mylib returns a loader function that accepts a callback
  loader( function( Isotope ) {
     //  now got Isotope, with packery layout mode loaded
    console.log( 'Isotope );
  });
});

mylib.js

define( [
    'require',
    'jquery',
    'path/to/isotope.pkgd.js'
  ],
  function( require, $, Isotope ) {
    // return this loader function
    return function( callback ) {
      require( [
          'jquery-bridget/jquery.bridget',
          'path/to/packery-mode.pkgd.js'
        ],
        function() {
          // Make .isotope() jQuery plugin
          $.bridget( 'isotope', Isotope );
          // callback triggered here
          callback( Isotope );
        }
      );
    }
});

For your example, I've left out imagesLoaded, as that can be loaded with either define or require call. I'm also using filepaths in the dependencies to simplify the example.

momolog commented 9 years ago

This works very well. It's a shame that index.js gets so complex, but good it is possible at all. Thanks!