Giter Club home page Giter Club logo

script.js's Introduction

$script.js - Async JavaScript loader & dependency manager

$script.js is an asynchronous JavaScript loader and dependency manager with an astonishingly impressive lightweight footprint. Like many other script loaders, $script.js allows you to load script resources on-demand from any URL and not block other resources from loading (like CSS and images). Furthermore, it's unique interface allows developers to work easily with even the most complicated dependencies, which can often be the case for large, complex web applications.

Browser Support

  • IE 6+
  • Opera 10+
  • Safari 3+
  • Chrome 1+
  • Firefox 2+

Examples

old school - blocks CSS, Images, AND JS!

<script src="jquery.js"></script>
<script src="my-jquery-plugin.js"></script>
<script src="my-app-that-uses-plugin.js"></script>

middle school - loads as non-blocking, but has multiple dependents

$script('jquery.js', function () {
  $script('my-jquery-plugin.js', function () {
    $script('my-app-that-uses-plugin.js')
  })
})

new school - loads as non-blocking, and ALL js files load asynchronously

// load jquery and plugin at the same time. name it 'bundle'
$script(['jquery.js', 'my-jquery-plugin.js'], 'bundle')

// load your usage
$script('my-app-that-uses-plugin.js')


/*--- in my-jquery-plugin.js ---*/
$script.ready('bundle', function() {
  // jquery & plugin (this file) are both ready
  // plugin code...
})


/*--- in my-app-that-uses-plugin.js ---*/
$script.ready('bundle', function() {
  // use your plugin :)
})

Exhaustive list of ways to use $script.js

$script('foo.js', function() {
  // foo.js is ready
})


$script(['foo.js', 'bar.js'], function() {
  // foo.js & bar.js is ready
})


$script(['foo.js', 'bar.js'], 'bundle')
$script.ready('bundle', function() {
  // foo.js & bar.js is ready
})

// create an id and callback inline
$script(['foo.js', 'bar.js'], 'bundle', function () {
  // foo.js & bar.js is ready
})


$script('foo.js', 'foo')
$script('bar.js', 'bar')
$script
  .ready('foo', function() {
    // foo.js is ready
  })
  .ready('bar', function() {
    // bar.js is ready
  })


var dependencyList = {
    foo: 'foo.js'
  , bar: 'bar.js'
  , thunk: ['thunkor.js', 'thunky.js']
}

$script('foo.js', 'foo')
$script('bar.js', 'bar')

// wait for multiple depdendencies!
$script.ready(['foo', 'bar', 'thunk'], function () {
  // foo.js & bar.js & thunkor.js & thunky.js is ready
}, function(depsNotFound) {
    // foo.js & bar.js may have downloaded
    // but ['thunk'] dependency was never found
    // so lazy load it now
    depsNotFound.forEach(function(dep) {
      $script(dependencyList[dep], dep)
    })
  })


// in my-awesome-plugin.js
$script.ready('jquery', function() {
  //define awesome jquery plugin here
  $script.done('my-awesome-plugin')
})

// in index.html
$script('jquery.js', 'jquery')
$script('my-awesome-plugin.js')
$script.ready('my-awesome-plugin', function() {
  //run code here when jquery and my awesome plugin are both ready
})

$script.path()

Optionally to make working with large projects easier, there is a path variable you can set to set as a base.

$script.path('/js/modules/')
$script(['dom', 'event'], function () {
  // use dom & event
});

Note that this will include all scripts from here on out with the base path. If you wish to circumvent this for any single script, you can simply call $script.get()

$script.path('/js/modules/')
$script(['dom', 'event'], function () {
  // use dom & event
})

$script.get('http://example.com/base.js', function () {

})

$script.urlArgs()

As of 2.5.5 it's possible to concat URL arguments (i.e. a query string) to the script path. This is especially useful when you're in need of a cachebuster and works as follows:

$script.urlArgs('key=value&foo=bar');

Please note that Squid, a popular proxy, doesn’t cache resources with a querystring. This hurts performance when multiple users behind a proxy cache request the same file – rather than using the cached version everybody would have to send a request to the origin server. So ideally, as Steve Souders points out, you should rev the filename itself.

Developers

Building a $script environment works like this:

npm install -dev
make

Ender support

You can add $script to your existing ender build by adding it as such:

ender add scriptjs

Get access to it as such:

$.require(...)

You can also require it as such:

var $S = require('scriptjs')

$S('/foo.js', function () {
  // foo is ready
})

script.js's People

Contributors

benekastah avatar boye avatar ded avatar fat avatar fat-bot avatar gorakhargosh avatar houkanshan avatar karlwestin avatar kneath avatar mikespock avatar sdaves avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

script.js's Issues

.js ending as option

I load my scripts with version ending for cache control purposes:

$script([
            "ready.min.js?1234"
          , "bonzo.min.js?1234"
          , "qwery.min.js?1234"
], 'dom');

But $script adds .js: ...ready.min.js?1234.js

Nothing criminal, but looks strange at least ) It'll be much better if there is an option, specify full filename with .js or only basename. Or maybe optional postfix, like path() does prefix.

Feature request: Enable '.js' class on the HTML element and HTML5 shim for html5 documents.

Placing $script.js in the head gives it an advantage of being
loaded before the document is rendered, and hence, can allow
CSS authors to target JS-enabled browsers and also can allow
HTML5 authors to use HTML5 elements in their documents.
Loading a separate script for these two reasons feels like a waste
of resources. It'd be great it $script.js can include these two features
as built-ins.

If it's acceptable, I can prepare a patch that adds these features.

Cheers!
Yesudeep.

More documentation please

Please add some documentation about the following:

  • Where to download script.js (is it in any package management system like npm?)
  • How to load script.js (I assume just your normal script tag)
  • What format loaded files need to be in (if any)
  • How do you access the resources after they're loaded? Are these scripts just run in the global scope and exposed in the same way they'd be if they were loaded in a script tag?
  • What is the actual footprint? You claim its footprint is impressively light, put a number here please so we can compare it to other loaders (minified and gzip compressed)

Please also add specifications for each function script.js exposes. Looks like this is just $script() $script.ready and $script.done. The examples you give don't explain well what exactly they do, and are pretty misleading. I would have expected $script.ready("file.js", function() {}) to load file.js and call the callback when its done. Instead, it doesn't do that at all, and requires a $script() call to happen first. This is entirely unclear.

Can't call $script() to load files from within a loaded file

I have a single line in my HTML file that calls $script('script'); in order to load my bootstrapper file which in turn calls $script() for all of my dependency files that I use.

Whenever I try to load something from within script.js, however, I get the following error:

'Uncaught TypeError: Cannot call method 'insertBefore' of null' from script.js on line 84

I could have sworn I had it working earlier, but now all I get is this error.

Any ideas what the cause could be?

Bug&Fix: Callbacks to unique dependencies (with same files) are not fired

Hi there,

I've encountered a bug in the current script.js version (unfortunately there is no version number anywhere).

How to reproduce

Create two separate script loader calls, which actually load the same scripts but with different dependency names. This happened for me when I loaded some controllers remotely, using $script.js for the controllers' dependency management. Both controllers are completely distinct, but have the same script dependencies.

Controller1:

$script(["file1.js","file2.js"], "controller1dependency");
$script.ready("controller1dependency", callback1);

Controller2:

$script(["file1.js","file2.js"], "controller2dependency");
$script.ready("controller2dependency", callback2);

Both controllers are loaded asynchronously, but before both file1.js and file2.js are fetched by $script.js. This is important: If the callback is added after both files are loaded, the callback works (instantly).

Behavior

Only one callback is called by script.js - the second one is ignored (though the callback function is registered in the internal delays object).

Reason

Seems that script.js is not saving the link between the dependency and the scripts to load for each dependency. Therefore, when the last script file of a dependency is fetched, it calls the callback of exactly this dependency - ignoring all the other dependencies which are waiting for this script.

Workaround

None that I could see.

Fix

I've created a small fix which works for me: Add a scriptsById variable in the head of the script.js (just where the doc variable is set) and replace the $script function with the following:

function $script(paths, idOrDone, optDone) {
    paths = paths[push] ? paths : [paths]
    var idOrDoneIsDone = idOrDone && idOrDone.call
      , done = idOrDoneIsDone ? idOrDone : optDone
      , id = idOrDoneIsDone ? paths.join('') : idOrDone
      , queue = paths.length
    function loopFn(item) {
      return item.call ? item() : list[item]
    }
    function callback() {
      if (!--queue) {
        list[id] = 1

        //Delete the loaded script from the scriptsById object - the callback is automatically called
        delete scriptsById[id];
        done && done()

        //FIX: We've to check every open script if it is loaded and if the corresponding id needs to be set to loaded
        for (var itemid in scriptsById) {
          var counter = 0;
          for (var scriptid in scriptsById[itemid]) {
            var scripturl = scriptsById[itemid][scriptid];
            if (scripts[scripturl] > 1) counter++;
          }
          if (counter >= scriptsById[itemid].length) {
            list[itemid] = 1;
            delete scriptsById[itemid];
          }
        }

        for (var dset in delay) {
          every(dset.split('|'), loopFn) && !each(delay[dset], loopFn) && (delay[dset] = [])
        }


      }
    }
    setTimeout(function () {
      //Save the path dependencies for every dependency
      scriptsById[id] = paths;


      each(paths, function (path) {
        if (path === null) return callback()
        if (scripts[path]) {
          id && (ids[id] = 1)
          return scripts[path] == 2 && callback()
        }
        scripts[path] = 1
        id && (ids[id] = 1)
        create(!validBase.test(path) && scriptpath ? scriptpath + path + '.js' : path, callback)
      })
    }, 0)
    return $script
  }

Happy for your feedback - and sorry that I didn't create a pull request out of that, I'm just too unexperienced in GIT ;)

Cheers,
Thomas

Tests Not Running Properly

I couldn't get the tests working in either Chrome 15 or FF 7 & 8 in OS X 10.7. I'm not sure what the problem is, as I didn't have a lot of time to debug it before I had to move on.

AngularJS breaking when using $script

I tried a few different methods to get angular working with $script, but the only way I could get it to work was to do normal <script> tag to load it.

I get the following errors when trying to use $script.

Uncaught TypeError: Object #<Object> has no method 'controller' controllers.js:2
Error: Argument 'AppController' is not a function, got undefined

I've also included my code in the below plunkr:
http://plnkr.co/edit/U6sUltGOU8IFsrzMAFay?p=preview

script.js not works on page reload

I have this structure:

<head>

<script type="text/javascript" src="js/script.js"></script>
<script type="text/javascript">
$script('http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js', 'jQuery');
</script>

So, just before </body> :

<script type="text/javascript">
$script('js/jquery-ui-tabs.min.js', 'jQuery_UI_Tabs');
$script('js/myfile.js');
</script>

And, inside myfile.js :

$script.ready(['jQuery', 'jQuery_UI_Tabs'], function(){
    $('#element').tabs({
        create: function(event, ui) { console.info('jQuery UI Tabs OK') }
    });
});

I have here a strange issue: when I enter in the page with script.load typing the URL address, all the process works very fine. BUT, if I press F5 or the reload button in the browser, the Firebug console shows me 2 errors:

  • "jQuery is not defined"
  • "$("#element").tabs is not a function"

Anyone have any idea about this weird issue?!

Delayed execution of ready event

In some situations it would be useful to not execute the ready event when the script has finished downloading and wait until it is called.

For example when loading google maps, the main google maps script needs to download other scripts before the maps api is ready. Google maps provides a callback for when it is ready, so this could be used to file the ready event for all scripts relying on the maps api.

A code example of how it could work:

// Download initial google maps js payload
loader('http://maps.google.com/maps/api/js?callback=googlemapsinit', 'maps', function() {
  // loader ready callback
  console.log('google maps api is ready');
});

// Google maps ready callback function, defined in url
googlemapsinit = function() {
  // Set ready state for google maps
  loader.ready('maps');
};

Ender Link Broken/Dangerous

You link to ender.no.de which is broken from the main readme file. Also ender.no is a virussy looking link.

Position of Javascript inclusion

Hi there,
in the current scriptjs version, Javascript resources are appended before title,meta and css resources of the page.

I think is better to include the javascript dependency after lastChild inside "head tag" to maintain the right structure of my html code.

FIX

In line 75:

head.insertBefore(el, head.firstChild);

instead of

head.insertBefore(el, head.lastChild);

Luciano

How to handle local fallbacks?

I am currently loading resources like jquery from google's CDN, but I have a fallback mechanism in place in case the CDN is unavailable:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.1.min.js">\x3C/script>')</script>

What would be the best way to accomplish this using $script? How is an action taken if a resource does not get loaded? Or what if the jquery.min.js file does get loaded, but for some reason it is empty or corrupt and doesn't define window.jQuery?

Feature: add the ability to remove scripts from the cache

In the source, the scripts variable holds a cache of all the scripts that have been loaded. Sometimes, if someone wants to hot-swap libraries out, they need the ability to clear this cache entry so that they can load a new version of the library in its place. I'd recommend something like $script.unload(path) to remove an item from the cache.

Problems loading 'index.js'

Is 'index.js' reserved on the client-side? Renaming the asset to app.js for example worked fine, is this a script.js issue or something related to Chrome of the ECMAScript spec?

Global vars fails to get declared on async loaded scripts

HTML

    <title>Backbone Views </title>
</head>
<body>
    <div id="placeholder">
    </div>
    <script type="text/javascript" src="scripts/script.js"></script>
    <script type="text/javascript" src="scripts/bbapp.js"></script>
</body>
</html>

BBAPP_JS

$script(["jquery.min", "underscore-min","backbone-min","models/bbapp_model","views/bbapp_view"], "bbApp");
$script.ready("bbApp", function () {
    $("document").ready(function () {
        var myModel = new Model();
        var myView = new View({
            "model": myModel,
            "el": $("#placeholder"),
            "className": "myDivTag",
            "tagName": "div",
            "id": "myID"
        });
    });
    //end dom ready
});
//end script ready

BBAPP_MODEL

$script(["underscore-min","backbone-min"],"model");
$script.ready("model", function () {
    window.ready = "I AM READY";
    Model = Backbone.Model.extend({
        initialize: function () {
            console.log("a new model has been created");
        },
        urlRoot: "/index.aspx",
        validate: function (attrs) {
        },
        sync: "requestManager",
        requestManager: function (method, model, success, error) {
            console.log("Model is Syncing", arguments);
        },
        onSuccess: function (model) {
        },
        onError: function (model) {
        }
    });
    //end backbone view
});
//end script ready

BBAPP_VIEW

$script(["underscore-min","backbone-min"],"view");
$script.ready("view", function () {
    window.ready = "I AM READY";
    View = Backbone.View.extend({
        defaults: {
        },
        initialize: function () {
            console.log("Initialized the Models View");
        },
        events: {
        },
        render: function () {
        },
        remove: function () {
        }
    });
    //end backbone view
});
//end script ready

ON FIREBUG CONSOLE

window.ready == undefinedis True

ie

IE_, in ender: $.script(['/socket.io/socket.io.js', 'foo.js'], function() { /_ the stuff exported via window.\* from foo.js is not defined here */ }). Later in the console that stuff is available. Tags are created, things do get loaded, but the timing i guess is wrong...
Any kludge how to fix?

TIA,
--Vladimir

Documentation inaccurate

The documentation shows to include the file extension ".js" in the call to $script... whereas the current build of $script automatically concatenates the .js extension, so these documented calls would fail.

[EXPIRED] Page-based loading

There are a lot of JS loaders, really. But none of them, at least within documentation, addresses a problem I'm eager to solve. That is to use single <script> line per whole project which inits page-based loading of dependencies.

Let's create a simple project with index, portfolio, and contacts pages.

Microframework will help us with routing:

$app->get('/portfolio/',
    function () use ($app) {
        $prices = array(
              "price_mine"  => "90",
              "price_rival" => "120"
        );
        $app->render('portfolio.twig', $prices);
    })->name('portfolio');

Template engine will help us with rendering:

{% extends "base.twig" %}
{% block content %}
     <p>Aren't you sick and tired to pay {{price_rival}}…</p>.
{% endblock content %}

And the missing part in every page is <script src="/static/init.js"></script> that works as follows

  • all pages load jQuery from CDN or from my server as fallback,
  • index loads SoundManager to serve audio salutation,
  • portfolio loads Lightbox to serve images,
  • contacts loads Forms validator.

What's the best way to achieve it?
And how to do that with $script.js whether it's possible?

Thank you in advance.
Warm regards from Russia, Alexander.

version number?

Hi, what's the version number of $script in master please? Apologies if it's in there, there's no tags and I couldn't find it in the other places I checked, thanks.

done() function

Hi!

Is there a way to get the result of loaded script execution into the callback? Say, $.script('foo', function(foo){ .., live foo here ... }). W/o this feature one has to spoil the global namespace, i presume.

TIA,
--Vladimir

Problem with ender

There is a problem with ender, nothing is getting exported with provide.

If a script is loaded twice, only one callback is called

When a script is loaded twice in a row, only one of the callbacks is returned.

$script('test.js', function() {
  console.log("hi")
})    
$script('test.js', function() {
  console.log("hi")
})

The output is only one "hi". If I instead set the second one with a timeout of 1 second, both callbacks are called. This is majorly broken.

Missing license

I can't find any reference to the license of this project.

Is this project released under the MIT, BSD, GPL, LGPL, Apache or WTFPL license? Or is it perhaps public domain?

I'm reluctant to use any code that doesn't contain any license details, as I need to be certain the code is compatible with the projects I'd like to include it in.

Please add some license details to the readme and/or as a separate file, so anyone interested in your code knows what we are legally allowed to use it for.

Providing a base path and loading absolute URLs

I always provide a base path pointing to the location where my JS files are located, but it makes loading files from an absolute URL more difficult (Must remember to use $script.get directly) and more limited ($script() adds a lot of nice things over $script.get that are lost when calling $script.get directly).

Wouldn't it make sense to check if a script path is a valid URL already before prepending the configured base path? I can't think of a scenario when someone would supply a base path, and then expect that it will be prepended when they supply an absolute URL to $script(). I think the expected functionality in at least the majority of cases would be that the base path is prepended only to relative URLs, while absolute URLs are passed through unaltered.

In its current state, supplying a base path makes loading JS from an absolute URL lose all the benefits that $script() adds on top of $script.get(), which seems like a bigger downside than the performance hit that making an extra string check in $script() would make. If performance is a worry, there could be a simple boolean setting in $script which tells it whether or not to check for absolute URLs, which could even default to off so that it works as it did before unless set.

What are your thoughts on this? Are there any other reasons that I'm overlooking for why that might not be preferred to the current functionality?

Thanks!

Fail safe way to load jQuery

How do i correctly load jQuery in a fail safe manner. Currently when disconnected from the internet and execute below script there is time-lag( for requesting jQuery from the CDN) and then all the plugin get loaded which depends on jquery. In the failure method there is code to load jQuery from another directory in the application which never gets executed.

How should this be done correctly?

$script("https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js", function () {
$script.path("Scripts/");
$script(["dropdown", "modal"]);
}, function () {
    $script("jquery.min.js")
});

Query - Are the js requests cached

I am providing the javascript requests from server with proper cache headers, but i don't know if these requests are cached. Does script.js provide any mechanism for caching or it is completely taken care by browsers. Can the script.js be used for Css too?

Make sure scripts and stylesheets are only loaded once

Just thinking out loud, I haven't done any testing or research on this yet. Feel free to close this issue if you see no merit.

It would be nice to make sure that a script isn't loaded more than once. I'm thinking this could be done by checking the DOM to see if any of the existing script tags has the same src as the script that is about to be loaded.

I'm currently using feature detection to avoid loading modules multiple times. This works for things like jquery, underscore, backbone, etc. This means I'm wrapping code around each $script call. And feature detection wouldn't really work for scripts that don't add some property to an object within the window tree.

My use case is different than most who are building standard web pages. I'm creating widgets that can be installed anywhere. Many of the widgets I'm building have the same dependencies and load several additional libraries (jquery, underscore, backbone, etc.). So it would be very easy to load the same resources multiple times when multiple widgets are placed on a page.

Bottom line is that if more than one widget is placed on the same page, I'd like to make sure they both don't load the same resources. Perhaps feature detection is the best solution. But maybe it makes sense for the loader to simply check if the src is already in the DOM.

Also, if my pull request to add $script.styles is incorporated, it would be nice to have a way that stylesheets aren't loaded more than once as well. That is much harder to detect with feature detection.

Callbacks are fired before scripts arrive...

<html>
  <head>
    <script>
    !function(a,b,c){function t(a,c){var e=b.createElement("script"),f=j;e.onload=e.onerror=e[o]=function(){e[m]&&!/^c|loade/.test(e[m])||f||(e.onload=e[o]=null,f=1,c())},e.async=0,e.src=a,d.insertBefore(e,d.firstChild)}function q(a,b){p(a,function(a){return!b(a)})}var d=b.getElementsByTagName("head")[0],e={},f={},g={},h={},i="string",j=!1,k="push",l="DOMContentLoaded",m="readyState",n="addEventListener",o="onreadystatechange",p=function(a,b){for(var c=0,d=a.length;c<d;++c)if(!b(a[c]))return j;return 1};!b[m]&&b[n]&&(b[n](l,function r(){b.removeEventListener(l,r,j),b[m]="complete"},j),b[m]="loading");var s=function(a,b,d){function o(){if(!--m){e[l]=1,j&&j();for(var a in g)p(a.split("|"),n)&&!q(g[a],n)&&(g[a]=[])}}function n(a){return a.call?a():e[a]}a=a[k]?a:[a];var i=b&&b.call,j=i?b:d,l=i?a.join(""):b,m=a.length;c(function(){q(a,function(a){h[a]?(l&&(f[l]=1),o()):(h[a]=1,l&&(f[l]=1),t(s.path?s.path+a+".js":a,o))})},0);return s};s.get=t,s.ready=function(a,b,c){a=a[k]?a:[a];var d=[];!q(a,function(a){e[a]||d[k](a)})&&p(a,function(a){return e[a]})?b():!function(a){g[a]=g[a]||[],g[a][k](b),c&&c(d)}(a.join("|"));return s};var u=a.$script;s.noConflict=function(){a.$script=u;return this},typeof module!="undefined"&&module.exports?module.exports=s:a.$script=s}(this,document,setTimeout)

      var cb = Math.random();
      var scripts = ["http://code.jquery.com/jquery-1.6.2.js?cb=" + cb];

      $script(scripts, function() {
        console.log(jQuery);
      });

      $script(scripts, function() {
        console.log(jQuery);
      });

      $script(scripts, function() {
        console.log(jQuery);
      });

      $script(scripts, function() {
        console.log(jQuery);
      });

      $script(scripts, function() {
        console.log(jQuery);
      });

    </script>
  </head>

  <body>
  </body>
</html>

Almost all callbacks fail in the above test case

Can loading and running be separated?

I have some dependencies that need to be executed in a certain order. It seems that I have to nest calls to $script to make scripts run in a specific order. Is this the case, or am I missing something?

Here's an example. I'm using Coffeescript in my app and refer to strings stored in this.libs attributes, so I hope you get the idea. Let me know if you need to see it in javascript.

deps = []
if not window.JSON
  $script @libs.json, 'json'
  deps.push 'json'
if not Array::map
  $script @libs.es5shim, 'es5shim'
  deps.push 'es5shim'
if not window._
  $script @libs.underscore, 'underscore'
  deps.push 'underscore'
if not window.jQuery
  $script self.libs.jquery, 'jquery'
  deps.push 'jquery'
if not window.Backbone
  $script self.libs.backbone, 'backbone'
  deps.push 'backbone'

$script.ready deps, ->
  # all dependencies should now be loaded

Unfortunately, Backbone uses underscore when it initially runs, so if underscore has not finished loading, errors occur. So I've had to do this:

self = @
deps = []

if not window.JSON
  $script @libs.json, 'json'
  deps.push 'json'
if not Array::map
  $script @libs.es5shim, 'es5shim'
  deps.push 'es5shim'
if not window._
  $script @libs.underscore, 'underscore'
  deps.push 'underscore'

$script.ready 'underscore', onUnderscore

onUnderscore = ->
  if not window.jQuery
    $script self.libs.jquery, 'jquery'
    deps.push 'jquery'
  if not window.Backbone
    $script self.libs.backbone, 'backbone'
    deps.push 'backbone'
  $script.ready deps, onDone

onDone = ->
  # all dependencies should now be loaded

Is there a better way to accomplish this?

It would be great if I could kick off the loading of everything without any nesting required. Then the call to ready would run the code in the order specified in the array. If multiple ready handlers dealt with the same script, the script would only be run once and would be flagged as already run and immediately accepted by any additional ready handlers.

If this is outside the scope of $script, just let me know. I know there are other loaders that can handle this, but $script holds a sweet spot for me at the moment.

File not found

Is there any way to know if file is not found (404)

Example

$script('someFileNotOnServer.js', function() {
/*
The code over here throws error.
*/
})

loop cacheing optimization results in extra iteration(s)/error in edge case

havent seen it break $script completely, but line 15 of script.js/src/script.js produces a console error if you have two different $script.ready calls, the first containing one file and the second containing two files:

function every(ar, fn, i) {
for (i = 0, j = ar.length; i < j; ++i) if (!fn(ar[i])) return f
return 1
}

the cacheing mechanism (j=ar.legnth) results in the return value being undefined. i fixed it on my end by just removing the third argument which doesnt seem to be used anyway and looping without the ar.length cacheing.

bad readyState regexp

I have noticed, that the reg expression for the readyState check is wrong. The regexp should seperate complete and loaded state from the other not loaded states (loading, uninitialized). Wich means the RegExp should return something like this (or vice versa):

    loaded: false
    complete: false

    uninitialized: true 
    loading: true

But currently returns the following:

    complete: true 
    loaded: false

    uninitialized: false 
    loading: false 

Javascript lazy loading

What would you say to:
$script.lazy('jquery-latest.min', 'jquery'); //just define a handler

//load when script is requested
$script.ready('jquery'....

Is it hard to implement?

bower support

A simple component.json file with a version number inside would be great (#43).

Bundling no longer working??

The README example says that you can bundle scripts into a name like so:

$script(['foo.js', 'bar.js'], 'bundle')

However, this does not seem to be working at the moment. I stepped through the code, but was having trouble determining where a bundled namespace is set or looked up.

$script is not defined on chrome in a local server

I did some tests to use your framework and I may found an issue.

I did some tests on Chrome 14.0.835.202 with demos/basic.html page.
When I run it with a file protocol everything works just fine.
When I run it with a http protocol on a local server, I get an error :
Uncaught ReferenceError: $script is not defined (Anonymous function) basic.html line 19

And I did check on firefox, it works fine on both file and http protocole.
Hope it helps

Problem in IE8 on local files (without server)

Local html file (runs without server, by drag & drop to browser; not tested with server)
script.min included in head (compressed with bananascript; also tested with script.js)

<script type="text/javascript" src="script.min.ban.js" charset="iso-8859-1"></script>

Test script in body (if with filename results are the same), tested in IE8, Chromium 12.0.730.0 (80877), Firefox 4

  • - alert shows
  • - alert doesn't show

Results:
IE8-
Chr+
FF4+

If I add $script(""); before test cases, it works in all browsers.

Test cases (used separately, not all at once):

(function() {

//1.
$script("", function() {
$script("", function() {
alert("test");
});
});

//2.
$script("test", "test");
$script.ready("test", function() {
alert("test");
});

//3.
$script("", function() {
alert("test");
});

})();

Update (not related to issue):
Possible feature to add (if it is possible in JavaScript): don't execute if error occured during loading script file (missing file for example).

Dependencies not loaded in time

Hi, So I'm running the following code:

    $script.path('assets/js/');
    //Load in dependencies
    $script(['libs/angular/angular.min', 'libs/jquery/jquery.min', 'libs/Responder/responder.min'], 'BaseFilesLoaded');
    //When dependecies are loaded run the main application code
    $script.ready('BaseFilesLoaded', function() {
        //Cache Dome elements
        var $body = $('body');


        // Responder is a jQuery plugin to add classes and trigger events based on defined break points (screen resolutions). 
        // https://github.com/Lane/Responder
        $body.responder();
    });

But I'm getting the following errors:

Uncaught ReferenceError: jQuery is not defined
Uncaught TypeError: Object [object Object] has no method 'responder'

This seems to suggest that despite the code being in the ready callback function, the files have still not loaded in. I hit refresh several times and the errors are intermittent.

Any idea how I can make sure the "ready" code does not get run until the dependencies are loaded in correctly?

Loading backbonejs with dependencies

How do i make the dependencies load one after another i did below but sometimes it just happens backbone.js is loaded first then underscore hence no extend,viewfunctionality.

$script(["jquery.min", "underscore-min", "backbone-min"], "mvc");
$script.ready("mvc", function () {
    $("document").ready(function () {
        });
    });
});

Allow option to set crossorigin attribute on script tags

To access the error message on window.onerror when loading js files from a different domain,
the crossorigin attribute has to be set on the script tags (+ headers "Access-Control-Allow-Origin" on the cdn naturally).

This only works in ff, but i think its coming in chrome soon as well.

Non-existant file still gets its success callback called

The following prints out "shouldnthappen"

$script('doesntExist.js', function() {
  console.log('shouldnthappen')
}, function(notFound) {
    console.log(notFound)
})

This makes me think script.js isn't in any way production ready.

Error loading multiple ordered files

In my index.html:

var domain = 'http://.../';
$script.path(domain);
$script('script/test', 'app');
$script.ready('app', function() {
  app.showCalendar();
  app.sumInputs();
});

Inside test.js I use module pattern http://www.yuiblog.com/blog/2007/06/12/module-pattern/

var _loadMoo = function () {
    $script('global/mootools/1.4.1/mootools-core', 'moo');
};

var _loadMooMore = function () {
    $script.order(['global/mootools/1.4.1/mootools-core', 'global/mootools/1.4.1/mootools-more'], 'mooMore');
};

showCalendar: function () {
  _loadMooMore();
  $script.ready('mooMore', function() {}

sumInputs: function () {
  _loadMooMore();
  $script.ready('mooMore', function() {console.log('x');

And console.log('x') is not executed. If You change order:

app.sumInputs();
 app.showCalendar();
$script.ready('mooMore', function() {console.log('show me calendar not executed');

I have rewritten all code to head.js to test if it is not my fault and worked like a charm.


Edit: I see that script.order() has something to do with my problem.

var _loadMoo = function () {
    $script('global/mootools/1.4.1/mootools-core', 'moo');
};

var _loadMooMore = function () {
_loadMoo();
$script.ready('moo', function() {
  $script('global/mootools/1.4.1/mootools-more', 'mooMore');
});

};

And that worked. Could You tell me why?

Feature: global cachebuster option

I am thinking about moving from require.js to $script as default script loader. Though, an option that I am currently missing is a way to easily 'cachebust' all scripts that are loaded by $script. Perhaps the following would be an option:

// In our staging and live env `app.cachebuster` holds the current rev number
// and acts as global cachebuster. So it would be nice to do something like:
$script.urlArgs('bust=' + app.cachebuster);

Is this something that's on the roadmap already?

Update: I took the liberty to add it myself :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.