Search code examples
javascriptjquerywebpack-2

jQuery plugins create 'not a function' error when loaded via Webpack


I recently led in implementing Webpack in our chaotic JavaScript directory in a Rails app. I won't give the backstory unless requested, but this is a recurring problem I haven't found a good solution to:

Our app uses jQuery and a handful of jQuery plugins. For this post, I'll use Froala Editor as the example. (https://www.froala.com/wysiwyg-editor)

The shortest description of the problem is this: upon loading the page that calls on froalaEditor, we're getting an error Uncaught TypeError: n(...).find(...).froalaEditor is not a function And trying to access the plugin after load yields a similar error.

Clearly the page doesn't have Froala correctly loaded. After a bit of logging and debugging, it seems like the Froala module imports jQuery and attaches to that instance of $, but is then overwritten when our app imports jQuery explicitly.

In terms of file structure and attempted solutions, we currently have a main js file that has our TextEditor module as a dependency. And in the TextEditor module, we require('froala-editor').

I've tried using imports-loader to force Froala to use a 'global' instance of jQuery, but it doesn't seem to matter.

module.exports = {
  test: require.resolve('froala-editor/js/froala_editor.pkgd.min.js'),
  use: [{
    loader: 'imports-loader?define=>false,exports=>false,jQuery=>jquery,$=>jquery,jquery=>jquery'
  }]
}

I've tried using ProvidePlugin:

plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      jquery: 'jquery'
    })
  ]

Also interestingly, the environment seems to change the results. I imagine it's just a load time thing, but if I just directly require('froala-editor') in our main js file, the problem seems to disappear locally, but stays broken in production.

Definitely at my wit's end with this thing, and since I'm not a Webpack pro, all the moving parts make this very difficult to debug.

Any help would be appreciated.


Solution

  • In the interest of helping anybody else who might come across this (pretty specific) issue...

    Local and production were behaving differently because production was consistently running yarn install at deploy. (I had run it fairly recently locally, but found myself using npm install to update packages). In a fun bit of chasing, I discovered that, despite the existence of yarn.lock, yarn will overwrite it anytime yarn install is run. It doesn't act much like my normal idea of a lock.

    So, long story short: something was askew in my yarn.lock file. I believe there may be an issue with an updated package, but after reverting the lockfile to a previously working commit, I was able to run yarn install and get things working okay.

    Definitely some stupidity on my part, but I think the way yarn uses the lockfile was totally unexpected and is worth sharing.