50

I have a bunch of JavaScript files that I would like to include in the page, but I don't want to have to keep writing

<script type="text/javascript" src="js/file.js"></script>

So is there a way to include all files in a directory (unknown size)? Can I do something like...

$.getScript("js/*.js");

... to get all the JavaScript files in the "js" directory? How can I do this using jQuery?

Hristo
  • 45,559
  • 65
  • 163
  • 230

10 Answers10

30

In general, this is probably not a great idea, since your html file should only be loading JS files that they actually make use of. Regardless, this would be trivial to do with any server-side scripting language. Just insert the script tags before serving the pages to the client.

If you want to do it without using server-side scripting, you could drop your JS files into a directory that allows listing the directory contents, and then use XMLHttpRequest to read the contents of the directory, and parse out the file names and load them.

Option #3 is to have a "loader" JS file that uses getScript() to load all of the other files. Put that in a script tag in all of your html files, and then you just need to update the loader file whenever you upload a new script.

Mark Bessey
  • 19,598
  • 4
  • 47
  • 69
  • I think this is the only way to do what the OP wants without server-side scripting. But I agree, it's better avoided. – harpo Nov 13 '10 at 22:29
  • I like Option #3 and I agree that it isn't a good option. However, I would like to get it to work first :) So how would I use `.getScript()` to get *all* the files in the directory? Can you provide some code? – Hristo Nov 13 '10 at 22:36
  • Hristo, I just meant that you could have one getScrip() call for each JavaScript file in the directory, then add a new entry each time a new file is added to the directory. – Mark Bessey Nov 13 '10 at 22:55
  • 4
    jellyfishtree, I don't think you're understanding what I'm saying - if the OP puts all of the JS files in a "scripts" directory, for example, then the javascript on their HTML page can just do an XmlHttpRequest for "http://example.com/scripts/", which would return a directory listing on the server. Then they can just parse the text of the response, and load each individual file. – Mark Bessey Nov 16 '10 at 21:25
  • It would be cool to do this, even if just for fun. It would allow the developer to drag and drop js files into a js folder and deploy their functions like an application. No code-writing needed. I can see some neato applications of this if it could be made to work. – Adam Grant Jun 18 '12 at 17:31
  • @MarkBessey note that you can compile file dependencies instead of hosting many files. This will be faster than having to load multiple files. – Loïc Faure-Lacroix Mar 15 '15 at 15:20
24

What about using a server-side script to generate the script tag lines? Crudely, something like this (PHP) -

$handle = opendir("scripts/");

while (($file = readdir($handle))!== false) {
    echo '<script type="text/javascript" src="' . $file . '"></script>';
}

closedir($handle);
znatno
  • 93
  • 9
jellyfishtree
  • 1,811
  • 1
  • 10
  • 11
  • eh... I would like to use this as a last resort. I prefer to not use PHP at the moment. – Hristo Nov 13 '10 at 22:25
  • I just don't think this is possible in Javascript because it has no access to any filesystem. Maybe an ActiveX Object, but users probably aren't gonna like this. – jellyfishtree Nov 14 '10 at 01:35
16

Given that you want a 100% client side solution, in theory you could probably do this:

Via XmlHttpRequest, get the directory listing page for that directory (most web servers return a listing of files if there is no index.html file in the directory).

Parse that file with javascript, pulling out all the .js files. This will of course be sensitive to the format of the directory listing on your web server / web host.

Add the script tags dynamically, with something like this:

function loadScript (dir, file) {
 var scr = document.createElement("script");
 scr.src = dir + file;
 document.body.appendChild(scr);
 }
rob
  • 9,933
  • 7
  • 42
  • 73
  • Alternatively, it's also possible to [load the files from a zip folder](https://stackoverflow.com/questions/37876051/opening-zip-files-in-browser-with-filereader-and-jszip-js) using FileReader. – Anderson Green Feb 12 '21 at 20:48
4

It can be done fully client side, but all javascript file names must be specified. For example, as array items:

function loadScripts(){
   var directory = 'script/';
   var extension = '.js';
   var files = ['model', 'view', 'controller'];  
   for (var file of files){ 
       var path = directory + file + extension; 
       var script = document.createElement("script");
       script.src = path;
       document.body.appendChild(script);
   } 
 }
Yuriy N.
  • 4,936
  • 2
  • 38
  • 31
  • liked your swift answer, and tuned it little bit below, I think you need to add the script to the head not the body, thanks – Hasan A Yousef Dec 14 '15 at 11:18
3

@jellyfishtree it would be a better if you create one php file which includes all your js files from the directory and then only include this php file via a script tag. This has a better performance because the browser has to do less requests to the server. See this:

javascripts.php:

<?php
   //sets the content type to javascript 
   header('Content-type: text/javascript');

   // includes all js files of the directory
   foreach(glob("packages/*.js") as $file) {
      readfile($file);
   }
?>


index.php:

<script type="text/javascript" src="javascripts.php"></script>

That's it!
Have fun! :)

Pascal
  • 41
  • 1
  • 3
3

You could use something like Grunt Include Source. It gives you a nice syntax that preprocesses your HTML, and then includes whatever you want. This also means, if you set up your build tasks correctly, you can have all these includes in dev mode, but not in prod mode, which is pretty cool.

If you aren't using Grunt for your project, there's probably similar tools for Gulp, or other task runners.

bwest87
  • 1,223
  • 13
  • 12
3

You can't do that in JavaScript, since JS is executed in the browser, not in the server, so it didn't know anything about directories or other server resources.

The best option is using a server side script like the one posted by jellyfishtree.

Alberto Martinez
  • 2,620
  • 4
  • 25
  • 28
  • 3
    Umm, getScript requires the path to the script, right? There's no magic. – harpo Nov 13 '10 at 22:28
  • 1
    You can't access private server resources from JS unless used along with some server side script, period. They are executed in different places (one at the client and the other at the server). – Alberto Martinez Nov 13 '10 at 22:39
1

You can't do that in Javascript from the browser... If I were you, I would use something like browserify. Write your code using commonjs modules and then compile the javascript file into one.

In your html load the javascript file that you compiled.

Loïc Faure-Lacroix
  • 13,220
  • 6
  • 67
  • 99
1

I was looking for an answer to this question and had my own problems. I found a couple solutions in various places and put them together into my own preferred answer.

function exploreFolder(folderURL,options){
/* options:                 type            explaination

    **REQUIRED** callback:  FUNCTION        function to be called on each file. passed the complete filepath
    then:                   FUNCTION        function to be called after loading all files in folder. passed the number of files loaded
    recursive:              BOOLEAN         specifies wether or not to travel deep into folders
    ignore:                 REGEX           file names matching this regular expression will not be operated on
    accept:                 REGEX           if this is present it overrides the `ignore` and only accepts files matching the regex
*/
$.ajax({
    url: folderURL,
    success: function(data){
        var filesLoaded = 0,
        fileName = '';

        $(data).find("td > a").each(function(){
            fileName = $(this).attr("href");

            if(fileName === '/')
                return;  //to account for the (go up a level) link

            if(/\/\//.test(folderURL + fileName))
                return; //if the url has two consecutive slashes '//'

            if(options.accept){
                if(!options.accept.test(fileName))
                    //if accept is present and the href fails, dont callback
                    return;
            }else if(options.ignore)
                if(options.ignore.test(fileName))
                    //if ignore is present and the href passes, dont callback
                    return;

            if(fileName.length > 1 && fileName.substr(fileName.length-1) === "/")
                if(options.recursive)
                    //only recurse if we are told to
                    exploreFolder(folderURL + fileName, options);
                else
                    return;

            filesLoaded++;
            options.callback(folderURL + fileName);
            //pass the full URL into the callback function
        });
        if(options.then && filesLoaded > 0) options.then(filesLoaded);
    }
});
}

Then you can call it like this:

var loadingConfig = {
    callback: function(file) { console.log("Loaded file: " + file); },
    then: function(numFiles) { console.log("Finished loading " + numFiles + " files"); },
    recursive: true,
    ignore: /^NOLOAD/,
};
exploreFolder('/someFolderURL/', loadingConfig);

This example will call that callback on every file/folder in the specified folder except for ones that start with NOLOAD. If you want to actually load the file into the page then you can use this other helper function that I developed.

function getFileExtension(fname){
    if(fname)
        return fname.substr((~-fname.lastIndexOf(".") >>> 0) + 2);
    console.warn("No file name provided");
}
var loadFile = (function(filename){
    var img = new Image();

    return function(){
        var fileref,
            filename = arguments[0],
            filetype = getFileExtension(filename).toLowerCase();

        switch (filetype) {
            case '':
                return;
            case 'js':
                fileref=document.createElement('script');
                fileref.setAttribute("type","text/javascript");
                fileref.setAttribute("src", filename);
                break;
            case "css":
                fileref=document.createElement("link");
                fileref.setAttribute("rel", "stylesheet");
                fileref.setAttribute("type", "text/css");
                fileref.setAttribute("href", filename);
                break;
            case "jpg":
            case "jpeg":
            case 'png':
            case 'gif':
                img.src = filename;
                break;
            default:
                console.warn("This file type is not supported: "+filetype);
                return;
        }
        if (typeof fileref !== undefined){
            $("head").append(fileref);
            console.log('Loaded file: ' + filename);
        }
    }
})();

This function accepts a JS | CSS | (common image) file and loads it. It will also execute the JS files. The complete call that needs to be run in your script to load all images and* stylesheets and other scripts could look like this:

loadingConfig = {
    callback: loadfile,
    then: function(numFiles) { console.log("Finished loading " + numFiles + " files"); },
    recursive: true,
    ignore: /^NOLOAD/,
};
exploreFolder('/someFolderURL/', loadingConfig);

It works amazingly!

Frozenfrank
  • 61
  • 1
  • 7
  • The one caveat to this is that it requires the server to publish a list of the files in its directory. There is a setting somewhere in your server settings that allows this, if it is disabled it is literally impossible to get what you want without server side code. – Frozenfrank May 16 '16 at 05:04
  • It is also dependent on jQuery to load the list of files (inside `exploreFolder`) and then load the files (inside `loadFile`). – Frozenfrank May 16 '16 at 05:07
1

Another option that is pretty short:

<script type="text/javascript">
$.ajax({
  url: "/js/partials",
  success: function(data){
     $(data).find('a:contains(.js)').each(function(){
        // will loop through 
        var partial= $(this).attr("href");
        $.getScript( "/js/partials/" + partial, function( data, textStatus, jqxhr ) {});
     });
  }
});
</script>
Alan
  • 2,046
  • 2
  • 20
  • 43