0

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.

9
  • 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? Commented Jul 9, 2013 at 13:50
  • 1
    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? Commented Jul 9, 2013 at 13:58
  • 1
    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? Commented Jul 9, 2013 at 14:12
  • 1
    Now, for my final line of inquiry. The plugin uses require. If the parent application does not use require, how is requirejs loaded? Commented Jul 9, 2013 at 14:20
  • 1
    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. Commented Jul 9, 2013 at 14:35

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

9 Comments

I apologize, I got kind of sidetracked from the actual problem. So the problem is that in my app.js file, the last snippet of code, $('#plugin').myPlugin(options) yields an error "Object has no method 'plugin'" and then immediately the plugin is loaded. I'm not sure why my plugin isn't being loaded prior to running the app.js code since plugin is listed as a dependency.
Because require creates its own version of jQuery and passes it around instead of using the global method. That's why I kept asking you if you are using the window.$ object or a shimmed jQuery. The example above will suss that out for you, and you can write your plugin as normal.
True. The problem I have though is that my makeplugin function uses AMD. See my edit.
Right, that's where the second if statement in my solution comes in. If the parent doesn't use require, it loads it, configures it and it becomes a global variable available to makeplugin.
Err, negative. define and define.amd are defined, but it does not load the module before executing the main app code, but after. See the edit.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.