corejavascript / typeahead.js

typeahead.js is a fast and fully-featured autocomplete library
https://typeahead.js.org/
MIT License
967 stars 231 forks source link

_.mixin is not a function #92

Open bramey opened 8 years ago

bramey commented 8 years ago

Using node and webstorm, when I start my app I get this error:

\nodemodules\corejs-typeahead\dist\typeahead.bundle.js:195 .mixin(LruCache.prototype, { ^

   TypeError: _.mixin is not a function

Has anyone else experianced this issue or know what causes it?

svbergerem commented 8 years ago

It's defined here: https://github.com/corejavascript/typeahead.js/blob/f8d3b77d9e3732f515635b30eb53aff3e7f80e3f/src/common/utils.js#L85.

bramey commented 8 years ago

Yes, I see it defined there locally too. Odd

bramey commented 8 years ago

I am still getting the same error however.

jony89 commented 7 years ago

i get the same thing

typeahead.bundle.js:217 _.mixin(LruCache.prototype, { ^

TypeError: _.mixin is not a function at \corejs-typeahead\dist\typeahead.bundle.js:217:11 at \corejs-typeahead\dist\typeahead.bundle.js:275:6 at \corejs-typeahead\dist\typeahead.bundle.js:13:26 at Object. (\corejs-typeahead\dist\typeahead.bundle.js:17:3)

jony89 commented 7 years ago

ok the problem (for me and probably for others as well) is that we run the code as well on the server side, for example rendering react on the server side and then serve html to the client.

since the code of jquery requires document :

function ( w ) {
    if ( !w.document ) {
        throw new Error( "jQuery requires a window with a document" );
    }
    return factory( w );
}

every function under $ is undefined, specifically $.extend and thus _.mixin is undefined

possible solutions :

  1. fetch typehead with lazy loading on client side only (can be done with split point, dynamic loading script with webpack) for react you could require this library at componentDidMount

  2. solution within the typehead library ?

jlbooker commented 7 years ago

@jony89 Thanks for the insight on this!

@bramey and @svbergerem, can either of you confirm that you're running this server-side?

I don't think this library was ever intended for server-side use, unfortunately. I'm open to reasonable sized patches, if that'll make it work for your use case, but do note that we may be getting beyond "intended use" here.

I'm not sure that you'll get around needing jQuery on the server, though. The best solution may be option #1 above (lazy loading on the client side). That will keep this code running on the client side as it was originally intended, and save the trouble of trying to make it compatible with server-side rendering.

bramey commented 7 years ago

Thank you @jony89 , I can confirm that I am running on server- side as well

On Fri, Dec 30, 2016 at 6:57 AM, Jeremy Booker notifications@github.com wrote:

@jony89 https://github.com/jony89 Thanks for the insight on this!

@bramey https://github.com/bramey and @svbergerem https://github.com/svbergerem, can either of you confirm that you're running this server-side?

I don't think this library was ever intended for server-side use, unfortunately. I'm open to reasonable sized patches, if that'll make it work for your use case, but do note that we may be getting beyond "intended use" here.

I'm not sure that you'll get around needing jQuery on the server, though. The best solution may be option #1 https://github.com/corejavascript/typeahead.js/pull/1 above (lazy loading on the client side). That will keep this code running on the client side as it was originally intended, and save the trouble of trying to make it compatible with server-side rendering.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/corejavascript/typeahead.js/issues/92#issuecomment-269774340, or mute the thread https://github.com/notifications/unsubscribe-auth/AGClqWFp3GuSzYoU19GHLCORhuLUnLvKks5rNQ3JgaJpZM4KTHgN .

jony89 commented 7 years ago

@jlbooker you may modify the library to use tools like underscore/lodash in order to run on the server side as well (function like extend are not dependent on the document obviously)

anyway, lazy loading the library on the client side worked for me, so it is an easy solution without modifying the module.

jlbooker commented 7 years ago

@jony89 This fork is mostly in a maintenance mode. We'll take new features if folks submit them, but none of the maintainers seem to be actively developing new features. I don't think anyone is going to undertake the major re-write necessary to replace jQuery with underscore/lodash. It would be a difficult PR to land given its size, complexity, and lack of backwards compatibility too. It's not impossible, but we'd need to be very careful with it. Given the effort needed, I don't see anyone starting on this.

jony89 commented 7 years ago

I am OK with leaving it like that for now.. just another suggestion, we can use something like jsdom to provide "document".

We can also ask in jQuery to provide an option for server side.

spapaseit commented 6 years ago

Hi @jony89, I know this is an old issue, but I'm running into the same problem.

I'm loading the module dynamically:

let module = await import("corejs-typeahead/dist/bloodhound");
let Bloodhound = module.Bloodhound;

But i never hit the second line because root is undefined. See this snippet from typeahead.bundle.js

function(root, factory) {
    if (typeof define === "function" && define.amd) {
        define([ "jquery" ], function(a0) {
            return root["Bloodhound"] = factory(a0);
        });
    } else if (typeof exports === "object") {
        module.exports = factory(require("jquery"));
    } else {
        root["Bloodhound"] = factory(root["jQuery"]);
    }
}

How did you manage to load this module dynamically without running into the same issue?

jony89 commented 6 years ago

by 'dynamically' i meant loading it on client side only. so for example in react I'm loading Bloodhound on the componentDidMount lifecycle which is not running on server side :

    componentDidMount() {
        this.Bloodhound = require('corejs-typeahead');
        this.initializeBloodhound();
    }

also I'm not sure why are you importing corejs-typeahead/dist/bloodhound rather than corejs-typeahead

spapaseit commented 6 years ago

Thank for your reply.

I'm loading the module dynamically as well, my import statement is on the attached() handler of an esNext module. I'm using Aurelia with Server Side Rendering, that's why using a classic import {Bloodhound} from "corejs-typeahead"; thows the original error in this post.

Here's the context in which I attempt the dynamic import.

async attached() {
        if (__aurelia__ssr__){
            return;
        }

        let module = await import("corejs-typeahead");
        let Bloodhound = module.Bloodhound;

     // ...
}

also I'm not sure why are you importing corejs-typeahead/dist/bloodhound rather than corejs-typeahead

Well, I was trying whether that would work, because importing corejs-typeahead gives exactly the same error: Cannot set property 'Bloodhound' of undefined, by which they mean root in the snippet of my previous comment.

But i guess you never ran into that one.