11

I would like ask some help because i can't convert my classic jQuery (v2) plugin in ES6 with module and class.

In ECMAScript 5, we can attach jQuery plugin into jQuery prototype like this :

app.js - jQuery loaded via HTML <script> tag

$.fn.myPlugin = function() {};
$('div').myPlugin();

And it works :) . In ES6, I would write something like this:

myPlugin.es6 :

import $ from 'jquery';

export default class myPlugin extends $ {
 // Could i use constructor() method ???
}

app.es6 :

import $ from 'jquery';
import myPlugin from 'myPlugin.es6';

$('div').myPlugin();

And finally, it's not working ...
I've search and no people ask this question before.
I use Babel to transpile ES6 into ES5.

loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
Robin Meillet
  • 293
  • 1
  • 3
  • 9
  • 1
    `extends $` makes no sense. Did you think it means the same as `$.extend({…})`? – Bergi Feb 02 '16 at 00:24
  • 1
    If you are looking at new Javascript features, you probably don't need jQuery. There is a lot of standalone UI-libraries that doesn't require jQuery. Also, there is a special website http://youmightnotneedjquery.com/ that explains how to switch from jQuery to native features. – just-boris Feb 04 '16 at 21:29

2 Answers2

15

$.fn is just an object. There is no magic upon adding a new property to the prototype of $. So, the code $.fn.myPlugin = function() {} is equal to $.prototype.myPlugin = function() {}.

$.fn === $.prototype; // true

To be able to call a function on the $ object in a standard way ($('div').func()), you need to add this function to the $ object.

You're not adding it in your es6 code.

Thus,

import $ from 'jquery';

export default class myPlugin extends $ {
 // Could i use constructor() method ???
}

Means (almost)

var myPlugin = function() {};

myPlugin.prototype = Object.create($.prototype);

return { default: myPlugin };

I'm not sure you should extend $.fn, but maybe you need it.

And with

import $ from 'jquery';
import myPlugin from 'myPlugin.es6';

it means

var $ = require('jquery');
var myPlugin = require('myPlugin'); // a reference to the 'export.default' object from 'myPlugin.es6'

Therefore, there is no connection between $.fn object and myPlugin function.

You should create the connection somewhere. It could be in a special module like plugins where you'll inject all needed plugins into the $.fn object:

import $ from 'jquery';
import plugin1 from 'plugin1.es6'; // should contain 'name'
import plugin2 from 'plugin2.es6';
...
import plugin10 from 'plugin10.es6';

[plugin1, plugin2, ..., plugin10].forEach(plugin => $.fn[plugin.name] = plugin);

Or you could add an 'initialize' method to the exported object in 'myPlugin.es6', and call it before first use: init($) { $.fn.myPlugin = myPlugin; }

And so on.

Microfed
  • 2,832
  • 22
  • 25
  • If a function is not anonymous, it has a name property. So your solution seems very good! I played with it on [Rollup sandbox](http://bit.ly/1T0Q4mU) – just-boris Feb 04 '16 at 21:31
  • I ended up doing almost the same thing in my code. Exporting by name: `export const myexport = { init: function ($) { /* code here */ } }` then `import { myexport } from './myexport.es6'; myexport.init($)`. – Neil Monroe Nov 16 '16 at 00:43
7

You install new methods on the jQuery prototype in ES6 just as you always did. Nothing has changed for them. You're not going to subclass jQuery, so it makes no sense to use class or extends.

// myPlugin.es6:
import $ from 'jquery';

$.fn.myPlugin = function() {
    …
};

// app.es6:
import $ from 'jquery';
import 'myPlugin.es6';

$('div').myPlugin();
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Doing it this way, do you have to mark the jquery dependency as a `peer dependency` in the `package.json` file of the plugin (`myPlugin.es6`)? Otherwise, how can you be sure that you and the consumer of your plugin both import the same `$` jQuery object? – tonix Mar 04 '20 at 07:18
  • @tonix Yes, if it's a separate library, that would make sense. – Bergi Mar 04 '20 at 08:49