0
votes

I've written a full web app and I bootstrap it with require in this line at the end of my HTML document:

<script src="js/vendor/require-2.1.6.min.js" data-main="js/main.js"></script>

Inside main.js, I declare my app using the following two functions:

requirejs.config({

    paths: {
        'jquery': 'vendor/jquery-1.9.1.min',
        'lodash': 'vendor/lodash-1.3.1.min',
        'knockout': 'vendor/knockout-2.2.1.min',
        'bootstrap': 'vendor/bootstrap-2.3.2.min'
    },
    shim: { 'bootstrap': { deps: ['jquery'] } }
});

requirejs(dependencies, function main(dependencies) { ... });

Now, I want to port my app as a jQuery plugin. As such, the end result I desire is to wrap my app in a jQuery fn,

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

modularize the code to compile into a single js file (plugin-1.0.0.min.js), include the code in another project, with or without AMD, and load my app into a div using

$('#pluginDiv').myPlugin({ options: {} }); 

First, do I need to change the requirejs/requirejs.config functions to declares in order to package my app as a modular component? Or do I simply leave my app like this? What about the config?

Next, how do I expose my plugin to the jQuery which the plugin user will be using, e.g. the one declared in the global scope? Will this work if they're using an AMD?

UPDATE

For question 1, I moved my requirejs.config to a build file, build.js, which requires some additional properties:

({
    baseUrl: ".",
    paths: {
        'jquery': 'vendor/jquery-1.9.1.min',
        'lodash': 'vendor/lodash-1.3.1.min',
        'knockout': 'vendor/knockout-2.2.1.min',
        'bootstrap': 'vendor/bootstrap-2.3.2.min'
    },
    shim: { 'bootstrap': { deps: ['jquery'] } },
    optimize: "none", // for debug
    name: "main",
    out: "plugin.js"
})

I was able to use r.js to compile this and it works great.

I am still stuck on question two, however. The code in my compiled myPlugin.js is as follows:

requirejs(dependencies, function main(dependencies) {
    (function($) {

        $.fn.myPlugin = function(options) {

            ...

            return this;
        };
    })(jQuery);
});

where dependencies does not include jQuery. Then, I bootstrap the app by calling:

<script src="js/vendor/require-2.1.6.min.js" data-main="js/app.js"></script>

And the code in app.js is

requirejs.config({
    paths: { 'jquery': 'vendor/jquery-1.9.1.min' },
    shim: { 'myPlugin': ['jquery'] }
});

requirejs(['jquery','myPlugin'], function main($) {
    $('#plugin').myPlugin(options);
});

However, my code always attempts to bind the plugin (from app.js), fails when the plugin is not a method on jQuery, and THEN loads the compiled plugin code and creates the method on jQuery. What's the problem here??

UPDATE 2

So, I've created a modular JavaScript file plugin.js using requirejs and its optimizer. The main code in the compiled plugin script,

requirejs(dependencies, function main(dependencies) {
    (function($) {
        $.fn.plugin = function(options) { return this; }
    })(window.jQuery);
);

doesn't get called until after the main code in the parent app:

requirejs(['jquery','plugin'], function main($) {
    $('#plugin').plugin({});
});

I assume this is because they are both making calls to requirejs. So the problem here is how to write my plugin such that it is usable within an AMD loader.

Sorry, I'm still figuring out the right questions to ask.

1
Let me see if I have your question correctly. You have a fancy plugin that uses require, but want to bind the plugin invocation to the main window.$ jquery object? - Thinking Sites
I'm still unclear about something. Are you trying to get this plugin to the window.$ or to the shimmed jQuery? Is require.js required for the parent application? - Thinking Sites
I think I see... your plugin is intended to be used as a shim, not the jquery object. Your plugin uses the jquery object, but you want it to use the global jquery object, not require's dependency jquery. Correct? - Thinking Sites
Now, for my final line of inquiry. The plugin uses require. If the parent application does not use require, how is requirejs loaded? - Thinking Sites
Not as far as I know. I haven't tried loading require from $.loadScript however. Let me play with that, and I'll have a solution for you later today. - Thinking Sites

1 Answers

1
votes

There is a pretty standard convention for modularizing plugins for use with and without requirejs. It looks something like this:

(function(){

    var makeplugin = function(dependancies){
        //do your plugin
    };

    if(define && define.amd) {
        defined(dependancies,function(dependancies){
            makeplugin(dependancies);
        });
    } else {
        makeplugin(dependancies)
    }
}());

Because your plugin uses require internally, but your parent app doesn't have to, you can load requirejs using $.getScript()

(function(){
    var makeplugin = function($){
        //do your plugin
    };

    if(define && define.amd) {
        // require is defined already, just use the plugin and have it load what it needs
        define(["jquery"],makeplugin);
    } else if(jQuery){
        // load require
        jQuery.getScript("/vendor/require",function(){
            require.config({
                // your config
            });
            makeplugin(jQuery);
        });
    } else {
        throw "requirejs or jquery are required for this plugin";
    }
}());

It isn't pretty but it should work.