Asyncronous JavaScript loader and dependency manager

Related tags

Loaders script.js
Overview

$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
})
Comments
  • $script.domReady doesn't work correctly in IE, Chrome, Opera, & Firefox.

    $script.domReady doesn't work correctly in IE, Chrome, Opera, & Firefox.

    Your $script.domReady() solution fails to work correctly in versions of IE, Chrome, Opera, & Firefox (http://jsbin.com/uxure5) and instead produces results similar to window.onload.

    opened by jdalton 31
  • Can loading and running be separated?

    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.

    opened by tauren 17
  • Support for loading CSS files

    Support for loading CSS files

    $script.js is great, but one thing I really miss from loaders like yepnope is the ability to load CSS files. Adding this to $script.js doesn't add much additional weight to the script.

    This is a useful feature for developing widgets that can be used on any site so that users installing the widget don't need to add anything into the header of their page.

    opened by tauren 15
  • Reducing size a bit more.

    Reducing size a bit more.

    Original:

    -rw-r--r--   1 gorakhargosh  staff  1199 Feb 24 15:11 script.js.gz
    -rw-r--r--   1 gorakhargosh  staff   834 Feb 24 15:11 script.min.js.gz
    

    Now:

    -rw-r--r--   1 gorakhargosh  staff  1176 Feb 24 15:12 script.js.gz
    -rw-r--r--   1 gorakhargosh  staff   823 Feb 24 15:12 script.min.js.gz
    

    I've run the tests in the browsers I have. I'd advise running them with all the browsers you're supporting and include this patch if it works in all of them.

    Keep up the good work.

    Cheers! Yesudeep.

    opened by gorakhargosh 12
  • Added bower.json

    Added bower.json

    This will provide better integration with https://github.com/yatskevich/grunt-bower-task. The most important here is "main" property which specifies the main file. Without it grunt-bower-task will copy whole repository to build folder.

    opened by marad 7
  • Non-existant file still gets its success callback called

    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.

    opened by fresheneesz 7
  • script.js not works on page reload

    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?!

    opened by tarciozemel 7
  • Callbacks are fired before scripts arrive...

    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

    opened by adomado 7
  • done() function

    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

    opened by dvv 7
  • Can't call $script() to load files from within a loaded file

    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?

    opened by bmcclure 6
  • Problem in IE8 on local files (without server)

    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)

    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).

    opened by Geist-zz 5
  • How to set attributes and data-* attributes with $script?

    How to set attributes and data-* attributes with $script?

    For example, I want the appended script tag to be:

    <script src="js/app.js" cross-origin="anonymous" integrity="..." data-something="peanut butter">
    
    opened by martynbiz 0
  • Checksum validation for better security

    Checksum validation for better security

    Loading third-party scripts via a loader gives us an opportunity to do checksum validation and avoid exploits made by bad third-party code. Idea is from this Twitter thread:

    image

    The checksum could be a self-descriptive multihash for future-proofing.

    opened by nileshtrivedi 1
  • Parms on Get

    Parms on Get

    How do I add parameters to the get function? i.e. scriptjs.get('https://api.addressfinder.io/assets/v3/widget.js', function (targetId) { console.log(targetId); });

    opened by marcuus 0
  • please add script onError callback !

    please add script onError callback !

      $script(url, function () {
          console.log('success');
        }, (error) => {
          console.log('error', error);
        })
    
    

    i need the fail callback to give the user the information that something load fail! but now it dont support !!

    or maybe you can provider the event to us!

      $script(url, function (e) {
         if(e.type === 'error') {
              console.log('error')
         } else {
               console.log('success');
        }
        },)
    
    
    opened by huyansheng3 0
Owner
Dustin Diaz
President, Founder at agent.com
Dustin Diaz
curl.js is small, fast, extensible module loader that handles AMD, CommonJS Modules/1.1, CSS, HTML/text, and legacy scripts.

curl (cujoJS resource loader) All development for curl.js and cram.js has stopped. For the foreseeable future, we will continue to respond to issues o

The Javascript Architectural Toolkit 1.9k Dec 30, 2022
:skull: An ancient tiny JS and CSS loader from the days before everyone had written one. Unmaintained.

LazyLoad Note: LazyLoad is no longer being maintained. I'm not responding to issues or pull requests, since I don't use this project anymore and don't

Ryan Grove 1.4k Jan 3, 2023
A Module Loader for the Web

A Module Loader for the Web Sea.js is a module loader for the web. It is designed to change the way that you organize JavaScript. With Sea.js, it is p

seajs 8.3k Jan 3, 2023
Dynamic ES module loader

SystemJS SystemJS is a hookable, standards-based module loader. It provides a workflow where code written for production workflows of native ES module

null 12.4k Dec 29, 2022
enterprise standard loader

ESL (Enterprise Standard Loader) ESL是一个浏览器端、符合AMD的标准加载器,适合用于现代Web浏览器端应用的入口与模块管理。 ESL is a browser-only, amd-compliant module loader. In modern web app

Baidu EFE team 833 Dec 16, 2022
Lightweight JavaScript module system.

modulejs Lightweight JavaScript module system. License The MIT License (MIT) Copyright (c) 2020 Lars Jung (https://larsjung.de) Permission is hereby g

Lars Jung 124 Dec 21, 2022
Meogic-tab-manager is an extensible, headless JavaScript tab manager framework.

MeogicTabManager English document MeogicTabManager是一个有可拓展性的、headless的JavaScript标签页管理框架。 MeogicTabManager旨在提供可自由组装页面框架、自定义页面组件、甚至覆盖框架自带事件响应的开发体验。 Meogi

meogic-tech 5 Oct 8, 2022
A devtool improve your pakage manager use experience no more care about what package manager is this repo use; one line, try all.

pi A devtool improve your pakage manager use experience no more care about what package manager is this repo use; one line, try all. Stargazers over t

tick 11 Nov 1, 2022
High performance and SEO friendly lazy loader for images (responsive and normal), iframes and more, that detects any visibility changes triggered through user interaction, CSS or JavaScript without configuration.

lazysizes lazysizes is a fast (jank-free), SEO-friendly and self-initializing lazyloader for images (including responsive images picture/srcset), ifra

Alexander Farkas 16.6k Jan 1, 2023
A file and module loader for JavaScript

RequireJS RequireJS loads plain JavaScript files as well as more defined modules. It is optimized for in-browser use, including in a Web Worker, but i

null 12.9k Dec 27, 2022
Customisable javascript skeleton loader.

JS Skeleton loader Simple but very powerful loader package built with full javascript. Installation To install this package, include index.js file int

A. M. Sadman Rafid 4 Dec 1, 2022
Finally, a simple, lightweight (0.6kb), pure JavaScript image lazy loader that even works in IE* using the IntersectionObserver API

Simply Lazy A simple & lightweight (0.6kb), pure JavaScript image lazy loader that even works in IE* utilizing the built in IntersectionObserver API i

Max 5 Dec 26, 2022
Three.js boilerplate project configured with typescript, webpack and css/style loader, HTTPS local server, and a sample test codes !!

three.js-boilerplate Welcome, this is a three.js boilerplate project where you can clone it and start to work !!! Installed and Configured Items: Type

pravin poudel 4 Jul 6, 2022
A dependency-free JavaScript ES6 slider and carousel. It’s lightweight, flexible and fast. Designed to slide. No less, no more

Glide.js is a dependency-free JavaScript ES6 slider and carousel. It’s lightweight, flexible and fast. Designed to slide. No less, no more What can co

null 6.7k Jan 7, 2023
A dependency-free JavaScript ES6 slider and carousel. It’s lightweight, flexible and fast. Designed to slide. No less, no more

Glide.js is a dependency-free JavaScript ES6 slider and carousel. It’s lightweight, flexible and fast. Designed to slide. No less, no more What can co

null 6.7k Jan 3, 2023
A tiny and fast zero-dependency date-picker built with vanilla Javascript and CSS.

A tiny zero-dependency and framework-agnostic date picker that is incredibly easy to use! Compatible with any web UI framework, vanilla JS projects, and even HTML-only projects!

Nezar 1 Jan 22, 2021
A script and resource loader for caching & loading files with localStorage

Basket.js is a script and resource loader for caching and loading scripts using localStorage ##Introduction for the Non-Developer Modern web applicati

Addy Osmani 3.4k Dec 30, 2022
curl.js is small, fast, extensible module loader that handles AMD, CommonJS Modules/1.1, CSS, HTML/text, and legacy scripts.

curl (cujoJS resource loader) All development for curl.js and cram.js has stopped. For the foreseeable future, we will continue to respond to issues o

The Javascript Architectural Toolkit 1.9k Dec 30, 2022
:skull: An ancient tiny JS and CSS loader from the days before everyone had written one. Unmaintained.

LazyLoad Note: LazyLoad is no longer being maintained. I'm not responding to issues or pull requests, since I don't use this project anymore and don't

Ryan Grove 1.4k Jan 3, 2023