addyosmani / basket.js

A script and resource loader for caching & loading files with localStorage
http://addyosmani.github.com/basket.js
MIT License
3.36k stars 276 forks source link

requirejs loading modules via basket.js #92

Open andrewwakeling opened 10 years ago

andrewwakeling commented 10 years ago

There's not much code and it works!

Is there a central place where these sorts of things can be referenced? I would be interested to see similar uses of basket.js such as this.

addyosmani commented 10 years ago

I'd like to start opening up basket.js to contributions of this sort, even if we're just documenting their existence - do you have more time to flesh this out a little?

andrewwakeling commented 10 years ago

This is just a throw-together. I'm happy to improve the code, put in some tests and turn it into a plug-in.

addyosmani commented 10 years ago

It looks like this might best exist as a dedicated RequireJS plugin. If you see yourself improving it/working on it in the future I'd recommend creating a separate open source project that we link to from the README, otherwise we could include it here but couldn't guarantee direct support for it from the team.

I like the first of these ideas most atm. Wdyt?

ffflabs commented 8 years ago

I know I shouldn't bring back this issue from the dead, but I wanted to comment on my experience with this. I tried @andrewwakeling code and sort of works for simple requirejs projects.

However, when we deal with several modules, each of them calling an anonymous define and meant to be optimized separately, it doesn't work. During the first load everything goes fine and every script is stored in localStorage. During the second load, everyone of these modules threw:

    mismatch Error: Mismatched anonymous define() module:

Which makes sense because they have an anonymous define inside of them, mind you.

So I tried turning this to a plugin.

define(function () {
    var frombasket = {
        load: function (name, parentRequire, parentLoad, config) {
            var fileUrl = parentRequire.toUrl(name + '.js');
            if (config.isBuild) {
                parentLoad();
                return;
            } else {
                basket.require({
                        url: fileUrl
                    }).then(function () {
                        parentRequire([name], function (value) {
                            parentLoad(value);
                            return;
                        });
                    }, function (error) {
                        return parentLoad.error(error);
                    });
            }
        }
    };
    return frombasket;
});

Which means that, instead of overriding requirejs.load method, I picked which modules to load with basketjs:

define([
   'frombasket!vendor/jquery.min',
   'frombasket!vendor/d3.min',
   'frombasket!vendor/handlebars.amd.min',
   'app/mymodule'
],function(jQuery, d3, Handlebars, myModule) {
   ...
});

But it was basically the same. Common libraries loaded ok, but unbuilt modules didn't. So I modified the plugin to have basketjs pass the raw code to requirejs:

define(function () {
    var frombasket = {
        load: function (name, parentRequire, parentLoad, config) {
            var fileUrl = parentRequire.toUrl(name + '.js');
            if (config.isBuild) {
                parentLoad();
                return;
            } else {
                basket.require({
                        url: fileUrl,
                        execute:false
                    }).then(function (result) {
                        parentLoad.fromText(result.data);

                        parentRequire([name], function (value) {
                            parentLoad(value);
                            return;
                        });
                    }, function (error) {
                        return onLoadNative.error(error);
                    });
            }
        }
    };
    return frombasket;
});

But it's even worse, because any dependencies in the form of named modules can't be resolved when you load a module with parentLoad.fromText. The main requirejs config, which contains the paths, isn't properly injected to the loaded and eval'd code.

So, for the time being, the first plugin code, as well as @andrewwakeling code, are safe to use only to store and request scripts that either are wrapped as UMD, or at least define themselves with an explicit name.