embroider-build / ember-auto-import

Zero config import from npm packages
Other
360 stars 108 forks source link

using jquery libraries #59

Closed mcfiredrill closed 6 years ago

mcfiredrill commented 6 years ago

Hi I'm trying to use masonry-layout with auto-import.

app/routes/blog.js

import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { schedule } from '@ember/runloop';
import $ from 'jquery';
import 'masonry-layout';

export default Route.extend({
  fastboot: service(),
  model: function(){
    return this.store.findAll('tumblr-post');
  },
  setupController: function(controller, model){
    this._super(controller, model);
    schedule('afterRender', this, function () {
      if(!this.get('fastboot.isFastBoot')){
        $('.grid').masonry({
          // options
          itemSelector: '.grid-item',
          columnWidth: 650,
          gutter: 20
        });
        $('.grid').imagesLoaded(function(){
          $(".grid").masonry();
        });
      }
    });
  }
});

I get this error, I guess because its trying to run masonry in fastboot maybe?

TypeError: Cannot read property 'prototype' of undefined
    at eval (webpack://__ember_auto_import__/./node_modules/desandro-matches-selector/matches-selector.js?:26:35)
    at Object.factory (webpack://__ember_auto_import__/./node_modules/desandro-matches-selector/matches-selector.js?:45:5)
    at ElemProto (webpack://__ember_auto_import__/./node_modules/desandro-matches-selector/matches-selector.js?:17:37)
    at eval (webpack://__ember_auto_import__/./node_modules/desandro-matches-selector/matches-selector.js?:22:2)
    at Object../node_modules/desandro-matches-selector/matches-selector.js (/Users/tony/src/datafruits/tmp/broccoli_merge_trees-output_path-5p1surf9.tmp/assets/vendor/ember-auto-import/app.js:108:1)
    at __webpack_require__ (/Users/tony/src/datafruits/tmp/broccoli_merge_trees-output_path-5p1surf9.tmp/assets/vendor/ember-auto-import/app.js:21:1)
    at utils (webpack://__ember_auto_import__/./node_modules/fizzy-ui-utils/utils.js?:15:7)
    at eval (webpack://__ember_auto_import__/./node_modules/fizzy-ui-utils/utils.js?:22:2)
    at Object../node_modules/fizzy-ui-utils/utils.js (/Users/tony/src/datafruits/tmp/broccoli_merge_trees-output_path-5p1surf9.tmp/assets/vendor/ember-auto-import/app.js:130:1)
    at __webpack_require__ (/Users/tony/src/datafruits/tmp/broccoli_merge_trees-output_path-5p1surf9.tmp/assets/vendor/ember-auto-import/app.js:21:1)
    at console (webpack://__ember_auto_import__/./node_modules/outlayer/outlayer.js?:16:9)
    at eval (webpack://__ember_auto_import__/./node_modules/outlayer/outlayer.js?:24:2)
    at Object../node_modules/outlayer/outlayer.js (/Users/tony/src/datafruits/tmp/broccoli_merge_trees-output_path-5p1surf9.tmp/assets/vendor/ember-auto-import/app.js:207:1)
    at __webpack_require__ (/Users/tony/src/datafruits/tmp/broccoli_merge_trees-output_path-5p1surf9.tmp/assets/vendor/ember-auto-import/app.js:21:1)
    at eval (webpack://__ember_auto_import__/./node_modules/masonry-layout/masonry.js?:15:9)
    at eval (webpack://__ember_auto_import__/./node_modules/masonry-layout/masonry.js?:23:2)
    at Object../node_modules/masonry-layout/masonry.js (/Users/tony/src/datafruits/tmp/broccoli_merge_trees-output_path-5p1surf9.tmp/assets/vendor/ember-auto-import/app.js:185:1)
    at __webpack_require__ (/Users/tony/src/datafruits/tmp/broccoli_merge_trees-output_path-5p1surf9.tmp/assets/vendor/ember-auto-import/app.js:21:1)
    at Module.eval [as callback] (webpack://__ember_auto_import__/./tmp/ember_auto_import_webpack-staging_dir-Hed12Pcm.tmp/entry.js?:4:61)
    at Module.exports (/Users/tony/src/datafruits/tmp/broccoli_merge_trees-output_path-5p1surf9.tmp/assets/vendor/loader/loader.js:106:1)
ef4 commented 6 years ago

Does your code work if you run it with FASTBOOT_DISABLED=true ember s?

(Also, I hope you're only serving fastboot to bots, because if you serve the HTML to users they're going to see everything weirdly jump when masonry finally takes over and runs in the browser.)

I think you're going to need to make sure masonry doesn't even try to load in fastboot because it won't work there. One thing you could try is to move import 'masonry-layout' into a browser-only initializer.

mcfiredrill commented 6 years ago

Does your code work if you run it with FASTBOOT_DISABLED=true ember s?

Thanks for the reply. I don't get that error anymore if I disable fastboot, however I am getting this error browser side. (Sorry I forgot to mention that originally.)

TypeError: Ember.$(...).masonry is not a function

I should be able to avoid loading masonry in fastboot to avoid the first error.

ef4 commented 6 years ago

I think I see what's going on here. masony and flickity (as reported in #68) install themselves via side-effect onto jQuery. We probably need to mark jQuery as an external dependency so they find the existing one rather than trying to pull in their own.

ef4 commented 6 years ago

My guess above was wrong, because neither of these things has a direct dependency on jQuery, because both consider it optional. They both have have documented steps that are required to make them work as jQuery plugins when building with webpack:

https://flickity.metafizzy.co/api.html#flickity-setjquery https://masonry.desandro.com/extras.html#webpack

If you follow those steps, both work with ember-auto-import. I confirmed by adding jquery-bridget, masonry-layout, and flickity to a project and putting this into app.js:

import $ from 'jquery';
import jQueryBridget from 'jquery-bridget';
import Masonry from 'masonry-layout';
import Flickity from 'flickity';

// flickity needs both of these steps to get full event support
Flickity.setJQuery( $ );
jQueryBridget( 'flickity', Flickity, $ );

// masonry just need this one
jQueryBridget( 'masonry', Masonry, $ );

After that you'll see that $('.something').masonry and $('.something').flickity are defined.

But my recommendation is to use these libraries directly, instead of plugging them into jQuery. Using them via jQuery buys you very little in an Ember app, because you already have the element, so you don't need jQuery to help find it:

import Flickity from 'flickity';
export default Component.extend({
  didInsertElement() {
    new Flickity(this.element, {
      // some options
    })
  }
});
MrChriZ commented 6 years ago

Thanks for this Ed