How do I include a JavaScript file in another JavaScript file?

4 360

1 335

Is there something in JavaScript similar to @import in CSS that allows you to include a JavaScript file inside another JavaScript file?

Alec Smart

Posted 2009-06-04T11:59:50.987

Reputation: 36 907

8Why not declaring the imported file before the other one that requires it, simply using ordered script tags? – falsarella – 2015-01-06T21:07:48.817

4@Claudiu That wouldn't help to import anything, but it should work as well. If you have a JS file that depends of another JS file, just declare the script tags of the dependency files first, so the later will already have its dependencies loaded. If you have a situation where it isn't a possible approach, the answers here should be helpful. – falsarella – 2016-02-19T12:29:41.483

what is the practical advantage of doing this? either way the code base dependent on javascript file isn't going to load and start working in any case it is not loaded ! – Ciasto piekarz – 2017-01-21T10:52:25.487

55@Daniel, I do not want to use an AJAX call. – Alec Smart – 2009-06-04T12:02:12.933

Answers

3 758

The old versions of JavaScript had no import, include, or require, so many different approaches to this problem have been developed.

But since 2015 (ES6), JavaScript has had the ES6 modules standard to import modules in Node.js, which is also supported by most modern browsers.

For compatibility with older browsers, build and/or transpilation tools can be used.

ES6 Modules

ECMAScript (ES6) modules have been supported in Node.js since v8.5, with the --experimental-modules flag. All files involved must have the .mjs extension.

// module.mjs
export function hello() {
  return "Hello";
}
// main.mjs
import { hello } from 'module'; // or './module'
let val = hello();  // val is "Hello";

ECMAScript modules in browsers

Browsers have had support for loading ECMAScript modules directly (no tools like Webpack required) since Safari 10.1, Chrome 61, Firefox 60, and Edge 16. Check the current support at caniuse.

<script type="module">
  import { hello } from './hello.mjs';
  hello('world');
</script>
// hello.mjs
export function hello(text) {
  const div = document.createElement('div');
  div.textContent = `Hello ${text}`;
  document.body.appendChild(div);
}

Read more at https://jakearchibald.com/2017/es-modules-in-browsers/

Dynamic imports in browsers

Dynamic imports let the script load other scripts as needed:

<script type="module">
  import('hello.mjs').then(module => {
      module.hello('world');
    });
</script>

Read more at https://developers.google.com/web/updates/2017/11/dynamic-import

Node.js require

The old style of importing modules, still widely used in Node.js, is the module.exports/require system.

// mymodule.js
module.exports = {
   hello: function() {
      return "Hello";
   }
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"   

There are other ways for JavaScript to include external JavaScript contents in browsers that do not require preprocessing.

AJAX Loading

You could load an additional script with an AJAX call and then use eval to run it. This is the most straightforward way, but it is limited to your domain because of the JavaScript sandbox security model. Using eval also opens the door to bugs, hacks and security issues.

jQuery Loading

The jQuery library provides loading functionality in one line:

$.getScript("my_lovely_script.js", function() {
   alert("Script loaded but not necessarily executed.");
});

Dynamic Script Loading

You could add a script tag with the script URL into the HTML. To avoid the overhead of jQuery, this is an ideal solution.

The script can even reside on a different server. Furthermore, the browser evaluates the code. The <script> tag can be injected into either the web page <head>, or inserted just before the closing </body> tag.

Here is an example of how this could work:

function dynamicallyLoadScript(url) {
    var script = document.createElement("script");  // create a script DOM node
    script.src = url;  // set its src to the provided URL

    document.head.appendChild(script);  // add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead)
}

This function will add a new <script> tag to the end of the head section of the page, where the src attribute is set to the URL which is given to the function as the first parameter.

Both of these solutions are discussed and illustrated in JavaScript Madness: Dynamic Script Loading.

Detecting when the script has been executed

Now, there is a big issue you must know about. Doing that implies that you remotely load the code. Modern web browsers will load the file and keep executing your current script because they load everything asynchronously to improve performance. (This applies to both the jQuery method and the manual dynamic script loading method.)

It means that if you use these tricks directly, you won't be able to use your newly loaded code the next line after you asked it to be loaded, because it will be still loading.

For example: my_lovely_script.js contains MySuperObject:

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

Then you reload the page hitting F5. And it works! Confusing...

So what to do about it ?

Well, you can use the hack the author suggests in the link I gave you. In summary, for people in a hurry, he uses an event to run a callback function when the script is loaded. So you can put all the code using the remote library in the callback function. For example:

function loadScript(url, callback)
{
    // Adding the script tag to the head as suggested before
    var head = document.head;
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}

Then you write the code you want to use AFTER the script is loaded in a lambda function:

var myPrettyCode = function() {
   // Here, do whatever you want
};

Then you run all that:

loadScript("my_lovely_script.js", myPrettyCode);

Note that the script may execute after the DOM has loaded, or before, depending on the browser and whether you included the line script.async = false;. There's a great article on Javascript loading in general which discusses this.

Source Code Merge/Preprocessing

As mentioned at the top of this answer, many developers use build/transpilation tool(s) like Parcel, Webpack, or Babel in their projects, allowing them to use upcoming JavaScript syntax, provide backward compatibility for older browsers, combine files, minify, perform code splitting etc.

e-satis

Posted 2009-06-04T11:59:50.987

Reputation: 348 932

174Just to be complete, there is a third way: In certain solutions when you control both javascript files, you can just make 1 giant javascript file which combines the content of both files. – Toad – 2012-09-07T08:36:00.277

2Loading scripts and posting forms through ajax are where jQuery shows its strength. – Michael Shopsin – 2012-09-21T15:45:09.627

15Shouldn't "document.createElement("my_lovely_script.js");" in the example be "document.createElement("script")" ? – Russell Silva – 2012-12-14T23:28:54.413

8How does eval open the door to hacks if it's your code that you're executing? – Vince Panuccio – 2013-01-06T09:39:09.890

I didn't say pirating, I said hack. For exemple, if you have code that have "use strict" in it, you will have to hack the hell out of it to make it work with eval. – e-satis – 2013-01-06T22:29:59.637

@e-satis I guess this import is a node.js thing, am I right?

– Trylks – 2013-07-11T10:43:31.363

1@Trylks Yes, there are several importers like this. Coffeescript got one as well. – e-satis – 2013-07-12T03:13:16.297

The events for script don't seem to fire in anything but IE (using XP so 8). Tried using addEventListener as well to no avail. – Dissident Rage – 2013-07-19T13:49:35.470

Someone should really mention the .onload JS native method in context of scripts relying on each other... – jave.web – 2013-08-11T08:28:02.530

2But my page does not know JQUERY This is exactly what I want to add!!! What to do? – lealam – 2013-10-01T05:06:50.043

// Here you can use anything you defined in the loaded script

I want to use functions includes in the loaded script everywhere after the use of getScript,

Can I do that?? – mfadel – 2013-11-05T13:55:48.780

Note: If you run loadScript before the document is loaded, you'll get an error like "Cannot call method 'appendChild' of null". – Luke – 2014-01-23T21:56:32.700

121Nope but somebody that uses something as advanced as Rhino or else wouldn't ask this question. – e-satis – 2010-07-15T03:53:21.037

Can't the whole problem of javascript files loading asynchronously be solved by simply putting the code that requires other javascript files inside of a window.onload function? – Bugalugs Nash – 2014-04-03T11:28:02.123

To work with IE8+ : http://msdn.microsoft.com/fr-fr/library/ie/hh180173(v=vs.85).aspx

– Lego – 2014-07-18T17:32:57.573

In the JavaScript Madness: Dynamic Script Loading webpage, I cannot really follow about the readyState bits. It says the states are quite nondeterministic (isn't it?) If yes, I have an idea of using setTimeout to keep checking the typeof functions until they are not "undefined". Is it good?

– midnite – 2014-09-24T08:28:59.743

@Toad I would agree with you but suppose one needs to load as less javascript (maybe for performance for rendering faster) as it can, what is better load a lot of javascript at once or just load on demand when it is needed? – albanx – 2014-10-22T12:57:14.550

@albanx as with all performance related questions: measure. 1 load of data always beats multiple requests if everything needs to be loaded anyway. But, as you say, certain things only need to be loaded when it is needed, then chunking it up is a lot faster for the initial load. So perceived performance goes up. No clear cut anwer for this one unfortunately. – Toad – 2014-10-23T11:43:41.813

The $.getScript(), seems to hang the browser until the the script is loaded. But this seems to happens only with some javascripts. I tried with tiny.mce.js – albanx – 2014-10-23T14:48:29.963

Note that jQuery 1.x does not fire error callbacks! jQuery 2.x does, but does not support IE <= 8 – Laurens Rietveld – 2014-12-10T16:17:53.997

@MichaelPaulukonis i'm using Javascript outside a browser can't I just use the features of a given shell / engine / interpreter? If I want to write standalone JS files and run them in Node, I imagine I can use require/ – user137717 – 2015-04-11T10:30:41.390

At the time I wrote my original comment (5 years ago) I had never heard of node, and was running JS on the command-line with the MS scripting library or whatever it was. The point still stands -- the answer is specifically browser-based while the question only says Javascript. So, node or other JS-engines seem applicable. – Michael Paulukonis – 2015-04-11T15:15:05.997

3

Your answer requires some modification for IE (onreadystatechange event and the readyState property). Also, dynamic script loading does not benefit from the broswer's preload scanners. Recommend this HTML5Rocks article: http://www.html5rocks.com/en/tutorials/speed/script-loading/

– ruhong – 2015-04-29T08:32:21.030

When I use this loadScript function, IE9 appears to be loading my script multiple times. – bkrall – 2015-06-15T23:21:57.113

I edited the question to point out that jQuery's getScript is not as useful as it first appeared to be, so take the previous comments with a pinch of salt. – Flimm – 2015-06-18T14:57:25.313

Soon we will have the native imports https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

– Andrew Clavin – 2016-07-05T05:56:51.990

Note that $.getScript adds an annoying anticache to the script url to prevent browser caching. Most people would want the script cached. jQuery 1.12.0 or later support disabling the anticache using this: $.getScript({url: "file.js",cache:true},callback) – oriadam – 2017-07-05T13:04:59.913

1Safari 10.1.2 on MacOS Sierra says SyntaxError: Unexpected keyword 'import'. – Cees Timmerman – 2017-10-03T15:43:50.633

The events do not work when using script type="module" to allow for ES6 imports. For a work around see this related SO question: https://stackoverflow.com/questions/47978809/how-to-dynamically-execute-eval-javascript-code-that-contains-an-es6-module-re

– Stefan – 2017-12-26T15:12:48.283

Why isn't just including the script on the HTML page before the 2nd script included as an option? The vast majority of the time, this makes perfect sense, and everything else is overkill. – KthProg – 2018-04-12T19:33:39.137

525

If anyone is looking for something more advanced, try out RequireJS. You'll get added benefits such as dependency management, better concurrency, and avoid duplication (that is, retrieving a script more than once).

You can write your JavaScript files in "modules" and then reference them as dependencies in other scripts. Or you can use RequireJS as a simple "go get this script" solution.

Example:

Define dependencies as modules:

some-dependency.js

define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {

     //Your actual script goes here.   
     //The dependent scripts will be fetched if necessary.

     return libraryObject;  //For example, jQuery object
});

implementation.js is your "main" JavaScript file that depends on some-dependency.js

require(['some-dependency'], function(dependency) {

    //Your script goes here
    //some-dependency.js is fetched.   
    //Then your script is executed
});

Excerpt from the GitHub README:

RequireJS loads plain JavaScript files as well as more defined modules. It is optimized for in-browser use, including in a Web Worker, but it can be used in other JavaScript environments, like Rhino and Node. It implements the Asynchronous Module API.

RequireJS uses plain script tags to load modules/files, so it should allow for easy debugging. It can be used simply to load existing JavaScript files, so you can add it to your existing project without having to re-write your JavaScript files.

...

John Strickler

Posted 2009-06-04T11:59:50.987

Reputation: 20 361

15+1 for citing the right way to do it :-) It would be even better if you included an example! – Sean Vieira – 2013-01-02T02:15:31.230

10@Sean per your suggestion - I added a short example – John Strickler – 2013-01-02T15:15:31.513

What exactly are d1 and d2 in some-dependency.js? – ashes999 – 2014-02-05T03:28:52.057

@ashes999 Library APIs for dependency1 and dependency2, respectively. So if dependency1 was, in fact, the jQuery library then it would be your jQuery API and you can name it whatever you want - such as $. – John Strickler – 2014-02-05T18:03:31.817

1@aaaidan: MattDmo's reason plus it relies on an external library which in return rely on the accepted answer. – David Mulder – 2014-03-20T21:28:06.420

1To overcome require.js the most latest would be angular js which is more stable and easy to use with along with other binding and rich HTML features. – zeeshan – 2014-11-17T20:00:40.883

3-1: Those abstractions -- "some_dependency" -- are really poor, with indexes adding to confusion. I struggle to understand what a working code example looks like. If author supplied working example, almost anybody would be able to tailor and generalize it to his needs. – Tegiri Nenashi – 2014-11-17T23:38:10.440

1doesn't work well with MVC and script bundling with automatic minification – Triynko – 2015-12-02T14:24:17.810

‘add .. w/o having to re-write your JavaScript files’; cool, but how exactly? Cur. answer suggests add such a ‘require’(not ‘requirejs’?) to main script +such a ‘define’ to every dependent file,yes? But that IS rewrite so what not rewritten? -rest of code since RequireJS lets ea file make global defs as normal? -does it? I just tried that, +(forgotten?) <script src="http://requirejs.org/docs/release/2.2.0/comments/require.js"&gt; </script>, then ‘requirejs(['http://GoogleDrive.com/host/..',..],function(a,b){mycode})’: Firebug says every dependent loaded BUT their defs not defined in mycode&after.

– Destiny Architect – 2016-05-16T04:11:51.450

@Triynko can you elaborate more? I'm playing with struts2 framework and thinking of giving RequireJS a go... Have you had bad experiences with it while using a MVC approach? RequireJS seems a bit overwhelming to me as I only need kind of "includes" on my JS files and I'm not developing a SPA, but It might be interesting to try it out – JorgeGRC – 2017-02-02T14:45:56.793

168

There actually is a way to load a JavaScript file not asynchronously, so you could use the functions included in your newly loaded file right after loading it, and I think it works in all browsers.

You need to use jQuery.append() on the <head> element of your page, that is:

$("head").append('<script type="text/javascript" src="' + script + '"></script>');

However, this method also has a problem: if an error happens in the imported JavaScript file, Firebug (and also Firefox Error Console and Chrome Developer Tools as well) will report its place incorrectly, which is a big problem if you use Firebug to track JavaScript errors down a lot (I do). Firebug simply doesn't know about the newly loaded file for some reason, so if an error occurs in that file, it reports that it occurred in your main HTML file, and you will have trouble finding out the real reason for the error.

But if that is not a problem for you, then this method should work.

I have actually written a jQuery plugin called $.import_js() which uses this method:

(function($)
{
    /*
     * $.import_js() helper (for JavaScript importing within JavaScript code).
     */
    var import_js_imported = [];

    $.extend(true,
    {
        import_js : function(script)
        {
            var found = false;
            for (var i = 0; i < import_js_imported.length; i++)
                if (import_js_imported[i] == script) {
                    found = true;
                    break;
                }

            if (found == false) {
                $("head").append('<script type="text/javascript" src="' + script + '"></script>');
                import_js_imported.push(script);
            }
        }
    });

})(jQuery);

So all you would need to do to import JavaScript is:

$.import_js('/path_to_project/scripts/somefunctions.js');

I also made a simple test for this at Example.

It includes a main.js file in the main HTML and then the script in main.js uses $.import_js() to import an additional file called included.js, which defines this function:

function hello()
{
    alert("Hello world!");
}

And right after including included.js, the hello() function is called, and you get the alert.

(This answer is in response to e-satis' comment).

Kipras

Posted 2009-06-04T11:59:50.987

Reputation: 1 897

I am trying this method, but is not working for me, the element just does not appear in head tag. – juanpastas – 2013-03-12T15:24:40.407

13

@juanpastas - use jQuery.getScript, that way you don't have to worry about writing the plugin...

– MattDMo – 2013-06-01T17:44:30.490

Does this technique really block until the imported script is both loaded and executed? – Flimm – 2015-06-18T14:28:36.900

4

Hmm, according to this article, appending a script element to head will cause it to run asynchronously, unless the async is specifically set to false.

– Flimm – 2015-06-18T15:36:07.027

Shouldn't the script variable have html entities encoded? If the link contains the ", code will break – SpookClover – 2017-08-31T13:55:18.677

I was looking for something like this so that I could use Jest & Node with some jquery javascript functions. I did something along the same idea... https://gist.github.com/peteristhegreat/5835942b6a31bdabf8e943b891395178

– phyatt – 2018-01-11T22:32:57.920

134

Another way, that in my opinion is much cleaner, is to make a synchronous Ajax request instead of using a <script> tag. Which is also how Node.js handles includes.

Here's an example using jQuery:

function require(script) {
    $.ajax({
        url: script,
        dataType: "script",
        async: false,           // <-- This is the key
        success: function () {
            // all good...
        },
        error: function () {
            throw new Error("Could not load script " + script);
        }
    });
}

You can then use it in your code as you'd usually use an include:

require("/scripts/subscript.js");

And be able to call a function from the required script in the next line:

subscript.doSomethingCool(); 

Ariel

Posted 2009-06-04T11:59:50.987

Reputation: 3 918

1Good solution, the head include is async unfortunately, the ajax solution works. – Matteo Conta – 2011-11-25T09:21:49.877

15As someone else mentioned, requirejs.org does this and also has a pre-compiler that puts js files together so they load faster. You may want to check it out. – Ariel – 2012-01-09T06:57:37.103

1Good solution. Seems to work. Keep in mind, the path you pass to require will be relative to the page your loading the scripts on, and not the scripts themselves. – BrainSlugs83 – 2012-07-21T10:00:46.683

1Correct. That's why I prefer absolute urls ;) – Ariel – 2012-07-24T00:02:25.457

I love this solution!. The phpjs library also has similar functions: link

– Cloudranger – 2012-10-11T09:22:33.217

1@Ariel -- I LOVE LOVE this BUT is there anyway to debug those required scripts? This would be the perfect solution if I could just step through my code still in Chrome. – Todd Vance – 2013-04-10T22:11:30.443

2Found I could do debug it by adding this directive at the bottom of the file for Chrome : //@ sourceURL=view_index.js – Todd Vance – 2013-04-11T00:02:09.437

9unfortunatelly, async:false is now deprecated in jQuery. Might break in the future, so i'd avoid. – sqram – 2013-10-17T01:45:50.750

1this is deprecated as of jquery 1.8, and does not work in jquery 1.9 – njzk2 – 2013-11-15T21:11:15.693

Works in 1.10.2 here. Is there another way to do it? – trusktr – 2014-03-31T05:10:35.827

@katsh (and njzk2): Please provide documentation for your claims. I believe you are mistaken, because the changelog and documentation only states that the usage of deferred/promise functionality is deprecated with $.ajax() and async: false and not the async: false functionality itself. This is the relevant ticket.

– Zero3 – 2015-04-22T19:38:04.240

1@Zero3 From the documentation. "The jqXHR objects returned by $.ajax() implement the Promise interface, giving them all the properties, methods, and behavior of a Promise. async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete" – sqram – 2015-04-27T12:23:47.230

3@katsh We are not using jqXHR objects here. Your quote doesn't seem to back up your previous comment stating that async: false supposedly is deprecated. It is not! As your quote states, only the jqXHR related stuff is. – Zero3 – 2015-04-27T16:50:40.013

You don't need jQuery for this. The Facebook button is a great example of very reliably loading an external script dynamically. Here's an answer based on their code.

– Dan Dascalescu – 2015-07-08T02:42:43.163

87

There is a good news for you. Very soon you will be able to load JavaScript code easily. It will become a standard way of importing modules of JavaScript code and will be part of core JavaScript itself.

You simply have to write import cond from 'cond.js'; to load a macro named cond from a file cond.js.

So you don't have to rely upon any JavaScript framework nor do you have to explicitly make Ajax calls.

Refer to:

Imdad

Posted 2009-06-04T11:59:50.987

Reputation: 4 755

8require/import on the jsfile has been way too long in the coming. (IMO). – rwheadon – 2013-04-10T16:12:04.330

5@rwheadon yeah seems appalling that this isnt part of the language! How js people get anything done is beyond me! Im new to it and this seems the worst (of many) bits of madness – Jonny Leeds – 2014-02-07T12:04:37.840

@jonny-leeds Even without built-in module-loading, JavaScript in the browser is flexible enough that we can implement a library like RequireJS for our module management. – Keen – 2014-05-02T15:06:13.303

7

mid 2015- Still not implemented in any browsers, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Browser_compatibility

– scape – 2015-07-02T16:14:33.827

yeah you are right. now I'm starting to feel bad for this :(. Thouh, once implemented in all browsers this will be a great feature built in to javascript. – Imdad – 2015-07-07T11:01:01.713

If you want to load scripts dynamically now, you'd better use a reliable method such as Facebook's script loading.

– Dan Dascalescu – 2015-07-08T02:43:26.473

@Imdad I saw many libraries on GitHub are using import now, but they still have a different version for browsers, which is most of the times library.min.js.... How do they convert their ES6 codes to ES5? – M98 – 2016-08-08T09:02:32.213

@Kermani, can you give me an example of such a library? – Imdad – 2016-08-11T13:32:44.003

Apparently this still isn't supported in browsers. I'm so incredibly surprised js wasn't designed with this functionality. I have like 10 js files that all depend on each other, I was trying to modularize my code. Come to find out there is no way to include these dependencies in a js file, so all my dependancies are defined in the html/php files that use only the top level js files. I really cannot believe js wasn't built with an include or require statement, and even harder to believe it still isn't working. please help. – gunslingor – 2016-10-21T01:32:30.487

@gunslingor As this is not supported by browsers yet why don't you try the solution proposed by @e-satis? – Imdad – 2016-11-10T09:36:58.053

@gunslingor You'd be surprised how many languages were designed to do something in a way that is unfamiliar to you. This usually means that you don't understand the language idioms, are Doing It Wrong(tm), or have just picked the wrong language for your task. With JavaScript though, you're not alone in thinking it needs some changes - and some of them have arrived with ES6 and others are coming. {On a related note, late 2017 and imports are just now being implemented...} – brichins – 2017-09-06T22:39:42.520

74

It is possible to dynamically generate a JavaScript tag and append it to HTML document from inside other JavaScript code. This will load targeted JavaScript file.

function includeJs(jsFilePath) {
    var js = document.createElement("script");

    js.type = "text/javascript";
    js.src = jsFilePath;

    document.body.appendChild(js);
}

includeJs("/path/to/some/file.js");

Svitlana Maksymchuk

Posted 2009-06-04T11:59:50.987

Reputation: 3 246

3@e-satis asynchronous is good because it wont freeze your page. Use callback to be notified when it's done js.onload = callback; – Vitim.us – 2013-08-23T15:40:56.137

Which again can be a problem if your page elements depends on JS for proper display. You have to choose carefully what you need before going async. – e-satis – 2013-08-23T15:52:32.623

@annakata, well, what if I need it to be synchronous ? – Francisco Corrales Morales – 2014-03-18T15:25:34.030

Sometimes, document.body might be null.

– Dan Dascalescu – 2015-07-08T02:48:46.077

2It does work, but has serious issues because of the asynchonous loading. – e-satis – 2009-06-04T12:11:12.290

Um... which exactly? – Svitlana Maksymchuk – 2009-06-04T12:14:31.690

5@e-satis - Actually, this is an advantage, a sync script would be blocking. Horses for courses, but 9 times in 10 you want the non-blocking option. – annakata – 2009-06-04T12:15:11.377

@Svitlana - script elements created like this are async. Currently this could be viewed as exploiting a loophole so it might not be future proof, I've not seen anything in any standard which clarifies this. – annakata – 2009-06-04T12:16:48.597

Actually I take it back, I've noticed you're appending to body rather than head. – annakata – 2009-06-04T12:19:49.870

@annakata: What is the difference? BTW, yahoo suggest to add script tags to the end of body, so nothing should wrong with it when appending dynamically. – Svitlana Maksymchuk – 2009-06-04T12:24:35.463

The difference is one is blocking (prevetns any further downloads) and one is not, and whilst yahoo suggests adding to the end of a document to improve percieved response times, it won't improve actual response times whilst the non-blocking version solves both problems (at the cost of having to code for async loads). – annakata – 2009-06-04T12:30:19.960

Well, the trouble is just that is you have MyObject defined in the script, you won't be able to use the line right after the line where you ask for the loading it. You will get a very troublesome and hard to understand MyObject is undefined, because when you "include" some code, you expect to use it... I give some more explanation in my answer. – e-satis – 2009-06-04T12:35:49.917

I like the simplicity of this approach. I modified it to I could ensure that I could call a function as soon as the secondary script was loaded. Here's an example of loading a file called 'outside.js', and calling a method within it in the same block. function readSeparateJavascriptFile() { var head = document.getElementsByTagName('head')[0]; var js = document.createElement('script'); js.type = 'text/javascript'; js.src = 'outside.js'; js.onload = function(){sayHello()}; //function in outside.js head.appendChild(js); } – quest4truth – 2018-02-02T16:11:46.603

59

Statement import is in ECMAScript 6.

Syntax

import name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import name , { member [ , [...] ] } from "module-name";
import "module-name" as name;

draupnie

Posted 2009-06-04T11:59:50.987

Reputation: 730

... but is not supported by any browser to date, according to the compatibility table on the page you linked to. – Zero3 – 2015-04-22T20:34:42.840

6

You can now write ES6 code and compile it with Babel.js (https://babeljs.io) to whatever your preferred current module system is (CommonJS/AMD/UMD): https://babeljs.io/docs/usage/modules/

– Jeremy Harris – 2015-06-12T20:35:13.973

@Zero3 Apparently the new IE (Edge) is the only one – Julian Avar – 2016-06-25T23:36:21.053

is there a way to do this without ES6? Browser compatibility and those who don't have ES6 demands it. – IamGuest – 2017-02-02T23:32:41.980

49

Maybe you can use this function that I found on this page How do I include a JavaScript file in a JavaScript file?:

function include(filename)
{
    var head = document.getElementsByTagName('head')[0];

    var script = document.createElement('script');
    script.src = filename;
    script.type = 'text/javascript';

    head.appendChild(script)
}

Arnaud Gouder de Beauregard

Posted 2009-06-04T11:59:50.987

Reputation: 984

4Should be useful to add script.onload = callback; – Vitim.us – 2013-08-23T15:37:34.247

@SvitlanaMaksymchuk so, if I don't use var, the variable will be global ? – Francisco Corrales Morales – 2014-03-18T15:22:56.113

@FranciscoCorrales yes. – Christopher Chiche – 2014-05-21T10:03:39.793

It ends up in global with or without the var :) – Vedran Maricevic. – 2015-01-16T08:27:44.523

This fails if the page has no head.

– Dan Dascalescu – 2015-07-08T02:50:19.907

This works asynchronously if you make the script explicitly async=false. See http://www.html5rocks.com/en/tutorials/speed/script-loading/#toc-dom-rescue

– chowey – 2015-11-22T23:20:47.493

You may add another line incase a custom attribute script.setAttribute('custom-attr', 'custom-id'); – Chetabahana – 2016-02-12T18:05:17.187

46

Here is a synchronous version without jQuery:

function myRequire( url ) {
    var ajax = new XMLHttpRequest();
    ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronous
    ajax.onreadystatechange = function () {
        var script = ajax.response || ajax.responseText;
        if (ajax.readyState === 4) {
            switch( ajax.status) {
                case 200:
                    eval.apply( window, [script] );
                    console.log("script loaded: ", url);
                    break;
                default:
                    console.log("ERROR: script not loaded: ", url);
            }
        }
    };
    ajax.send(null);
}

Note that to get this working cross-domain, the server will need to set allow-origin header in its response.

heinob

Posted 2009-06-04T11:59:50.987

Reputation: 5 400

Excellent function! Loads the JavaScript before any additional JS is written after the body. Very important when loading multiple scripts. – tfont – 2014-02-28T21:50:39.857

3@heinob : What can I do to get it working for cross-domain? (loading script from http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js) – user2284570 – 2014-09-14T02:20:49.123

@user2284570: If you are the owner of the foreign domain: set `allow-origin' header in server answer. If you are'nt the owner: nothing. Sorry! That is cross-origin-policy. – heinob – 2014-09-14T05:42:57.760

@heinob : No because, this is for a user script! (need to load this script : http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js) – user2284570 – 2014-09-14T09:53:54.653

2@user2284570: I understand your comment in that way, that you are not the owner of the domain from which you want to load the script. In that case you only can load a script via an inserted &lt;script&gt; tag, not via XMLHttpRequest. – heinob – 2014-09-14T16:10:58.857

@heinob : you're right, but you can't access html directly in Greasmonkey, and I didn't to load it only if GM_ functions doesn't exists (dynamic loading). – user2284570 – 2014-09-14T19:28:08.183

2For those planning to use this in Firefox (say for imacros scripting), add this line to the top of the file: const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1"); – Kwestion – 2016-03-16T00:16:29.297

42

I just wrote this JavaScript code (using Prototype for DOM manipulation):

var require = (function() {
    var _required = {};
    return (function(url, callback) {
        if (typeof url == 'object') {
            // We've (hopefully) got an array: time to chain!
            if (url.length > 1) {
                // Load the nth file as soon as everything up to the
                // n-1th one is done.
                require(url.slice(0, url.length - 1), function() {
                    require(url[url.length - 1], callback);
                });
            } else if (url.length == 1) {
                require(url[0], callback);
            }
            return;
        }
        if (typeof _required[url] == 'undefined') {
            // Haven't loaded this URL yet; gogogo!
            _required[url] = [];

            var script = new Element('script', {
                src: url,
                type: 'text/javascript'
            });
            script.observe('load', function() {
                console.log("script " + url + " loaded.");
                _required[url].each(function(cb) {
                    cb.call(); // TODO: does this execute in the right context?
                });
                _required[url] = true;
            });

            $$('head')[0].insert(script);
        } else if (typeof _required[url] == 'boolean') {
            // We already loaded the thing, so go ahead.
            if (callback) {
                callback.call();
            }
            return;
        }

        if (callback) {
            _required[url].push(callback);
        }
    });
})();

Usage:

<script src="prototype.js"></script>
<script src="require.js"></script>
<script>
    require(['foo.js','bar.js'], function () {
        /* Use foo.js and bar.js here */
    });
</script>

Gist: http://gist.github.com/284442.

nornagon

Posted 2009-06-04T11:59:50.987

Reputation: 7 991

Isn't this putting the loaded script outside of the scope where require() is called? Seems like eval() is the only way to do it within scope. Or is there another way? – trusktr – 2014-03-31T03:35:26.270

7

jrburke wrote this as RequireJS. Github: http://requirejs.org/docs/requirements.html

– Mike Caron – 2011-09-14T17:14:26.413

34

Here's the generalized version of how Facebook does it for their ubiquitous Like button:

<script>
  var firstScript = document.getElementsByTagName('script')[0],
      js = document.createElement('script');
  js.src = 'https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js';
  js.onload = function () {
    // do stuff with your dynamically loaded script
    snowStorm.snowColor = '#99ccff';
  };
  firstScript.parentNode.insertBefore(js, firstScript);
</script>

If it works for Facebook, it will work for you.

The reason why we look for the first script element instead of head or body is because some browsers don't create one if missing, but we're guaranteed to have a script element - this one. Read more at http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/.

Dan Dascalescu

Posted 2009-06-04T11:59:50.987

Reputation: 64 585

3Damn nice! Some of the methods here work too, but under a dynamic setting this works the best. – tfont – 2016-07-13T15:51:34.457

29

If you want in pure JavaScript, you can use document.write.

document.write('<script src="myscript.js" type="text/javascript"></script>');

If you use the jQuery library, you can use the $.getScript method.

$.getScript("another_script.js");

Venu immadi

Posted 2009-06-04T11:59:50.987

Reputation: 1 290

6wouldn't document.write remove everything else? – Eisa Adil – 2014-01-14T00:53:51.323

23

Most of solutions shown here imply dynamical loading. I was searching instead for a compiler which assemble all the depended files into a single output file. The same as Less/Sass preprocessors deal with the CSS @import at-rule. Since I didn't find anything decent of this sort, I wrote a simple tool solving the issue.

So here is the compiler, https://github.com/dsheiko/jsic, which replaces $import("file-path") with the requested file content securely. Here is the corresponding Grunt plugin: https://github.com/dsheiko/grunt-jsic.

On the jQuery master branch, they simply concatenate atomic source files into a single one starting with intro.js and ending with outtro.js. That doesn't suits me as it provides no flexibility on the source code design. Check out how it works with jsic:

src/main.js

var foo = $import("./Form/Input/Tel");

src/Form/Input/Tel.js

function() {
    return {
          prop: "",
          method: function(){}
    }
}

Now we can run the compiler:

node jsic.js src/main.js build/mail.js

And get the combined file

build/main.js

var foo = function() {
    return {
          prop: "",
          method: function(){}
    }
};

Dmitry Sheiko

Posted 2009-06-04T11:59:50.987

Reputation: 992

2

Since this post I came up with much better solution - CommonJS module compiler - https://github.com/dsheiko/cjsc So you can simply write CommonJs or NodeJs modules and access each other yet keeping them in isolated scopes. The benefits: No need of multiple HTTP requests that affect performance You don't need manually wrapping you module code - it is responsibility of the compiler (so better source code readability) You don't need any external libraries It is compatible with UMD- and NodeJs modules (e.g. you can address jQuery, Backbone as modules without touching their code)

– Dmitry Sheiko – 2014-03-07T16:07:24.570

23

You can also assemble your scripts using PHP:

File main.js.php:

<?php
    header('Content-type:text/javascript; charset=utf-8');
    include_once("foo.js.php");
    include_once("bar.js.php");
?>

// Main JavaScript code goes here

Calmarius

Posted 2009-06-04T11:59:50.987

Reputation: 8 403

1Thanks for reminding this. You can also have PHP write <script> tags in your HTML header, so that the js files you need (and only those) will be loaded. – Rolf – 2013-12-18T12:38:45.477

16Sounds like the point is to keep this all in javascript in the front end – Ariel – 2011-09-08T18:23:28.790

19

If your intention to load the JavaScript file is using the functions from the imported/included file, you can also define a global object and set the functions as object items. For instance:

global.js

A = {};

file1.js

A.func1 = function() {
  console.log("func1");
}

file2.js

A.func2 = function() {
  console.log("func2");
}

main.js

A.func1();
A.func2();

You just need to be careful when you are including scripts in an HTML file. The order should be as in below:

<head>
  <script type="text/javascript" src="global.js"></script>
  <script type="text/javascript" src="file1.js"></script>
  <script type="text/javascript" src="file2.js"></script>
  <script type="text/javascript" src="main.js"></script>
</head>

Adem İlhan

Posted 2009-06-04T11:59:50.987

Reputation: 785

17

This should do:

xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);

tggagne

Posted 2009-06-04T11:59:50.987

Reputation: 1 997

5

the eval is what's wrong with it. From Crockford, "eval is evil. The eval function is the most misused feature of JavaScript. Avoid it. eval has aliases. Do not use the Function constructor. Do not pass strings to setTimeout or setInterval." If you haven't read his "JavaScript: The Good Parts" then go out and do it right now. You will not regret it.

– MattDMo – 2013-06-01T17:56:21.750

+1, but I ran into one problem that global variables are not defined. Although functions are imported fine. Ok, it seems JS isn't C++ so we should give up our tries and accept js as it is – Tebe – 2013-11-25T23:12:06.730

11@MattDMo "Someone said it was bad" isn't really an argument. – Casey – 2014-09-03T19:05:36.120

4

@emodendroket I take it you're not aware of who Douglas Crockford is.

– MattDMo – 2014-09-03T19:24:54.080

12@MattDMo I'm fully aware of who he is, but he's a human being, not a god. – Casey – 2014-09-03T19:52:38.530

2@tggagne : What can I do to get it working for cross-domain? (loading script from http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js) – user2284570 – 2014-09-14T02:18:24.430

16

Or rather than including at run time, use a script to concatenate prior to upload.

I use Sprockets (I don't know if there are others). You build your JavaScript code in separate files and include comments that are processed by the Sprockets engine as includes. For development you can include files sequentially, then for production to merge them...

See also:

JMawer

Posted 2009-06-04T11:59:50.987

Reputation: 169

Browserify is far more popular than Sprockets. – Dan Dascalescu – 2015-07-08T02:52:06.563

13

In case you are using Web Workers and want to include additional scripts in the scope of the worker, the other answers provided about adding scripts to the head tag, etc. will not work for you.

Fortunately, Web Workers have their own importScripts function which is a global function in the scope of the Web Worker, native to the browser itself as it is part of the specification.

Alternatively, as the second highest voted answer to your question highlights, RequireJS can also handle including scripts inside a Web Worker (likely calling importScripts itself, but with a few other useful features).

Turnerj

Posted 2009-06-04T11:59:50.987

Reputation: 3 485

12

I had a simple issue, but I was baffled by responses to this question.

I had to use a variable (myVar1) defined in one JavaScript file (myvariables.js) in another JavaScript file (main.js).

For this I did as below:

Loaded the JavaScript code in the HTML file, in the correct order, myvariables.js first, then main.js:

<html>
    <body onload="bodyReady();" >

        <script src="myvariables.js" > </script>
        <script src="main.js" > </script>

        <!-- Some other code -->
    </body>
</html>

File: myvariables.js

var myVar1 = "I am variable from myvariables.js";

File: main.js

// ...
function bodyReady() {
    // ...
    alert (myVar1);    // This shows "I am variable from myvariables.js", which I needed
    // ...
}
// ...

As you saw, I had use a variable in one JavaScript file in another JavaScript file, but I didn't need to include one in another. I just needed to ensure that the first JavaScript file loaded before the second JavaScript file, and, the first JavaScript file's variables are accessible in the second JavaScript file, automatically.

This saved my day. I hope this helps.

Manohar Reddy Poreddy

Posted 2009-06-04T11:59:50.987

Reputation: 4 466

The problem with this answer is that it is not something like import. You need an HTML file to get stuff from one js file to another. – IamGuest – 2017-02-02T23:34:27.510

Agreed. What is your use case? – Manohar Reddy Poreddy – 2017-02-03T04:27:48.567

11

The @import syntax for achieving CSS-like JavaScript importing is possible using a tool such as Mixture via their special .mix file type (see here). I imagine the application simply uses one of the aforementioned methods interally, though I don't know.

From the Mixture documentation on .mix files:

Mix files are simply .js or .css files with .mix. in the file name. A mix file simply extends the functionality of a normal style or script file and allows you to import and combine.

Here's an example .mix file that combines multiple .js files into one:

// scripts-global.mix.js
// Plugins - Global

@import "global-plugins/headroom.js";
@import "global-plugins/retina-1.1.0.js";
@import "global-plugins/isotope.js";
@import "global-plugins/jquery.fitvids.js";

Mixture outputs this as scripts-global.js and also as a minified version (scripts-global.min.js).

Note: I'm not in any way affiliated with Mixture, other than using it as a front-end development tool. I came across this question upon seeing a .mix JavaScript file in action (in one of the Mixture boilerplates) and being a bit confused by it ("you can do this?" I thought to myself). Then I realized that it was an application-specific file type (somewhat disappointing, agreed). Nevertheless, figured the knowledge might be helpful for others.

UPDATE: Mixture is now free (offline).

UPDATE: Mixture is now discontinued. Old mixture releases are still available

Isaac Gregson

Posted 2009-06-04T11:59:50.987

Reputation: 801

This would be awesome if it were a node module. – b01 – 2015-04-19T19:07:32.390

@b01 Sounds like a challenge ;) If only I had the time... perhaps someone else does? – Isaac Gregson – 2016-04-06T10:05:59.103

10

I wrote a simple module that automates the job of importing/including module scripts in JavaScript. For detailed explanation of the code, refer to the blog post JavaScript require / import / include modules.

// ----- USAGE -----

require('ivar.util.string');
require('ivar.net.*');
require('ivar/util/array.js');
require('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js');

ready(function(){
    //Do something when required scripts are loaded
});

    //--------------------

var _rmod = _rmod || {}; //Require module namespace
_rmod.LOADED = false;
_rmod.on_ready_fn_stack = [];
_rmod.libpath = '';
_rmod.imported = {};
_rmod.loading = {
    scripts: {},
    length: 0
};

_rmod.findScriptPath = function(script_name) {
    var script_elems = document.getElementsByTagName('script');
    for (var i = 0; i < script_elems.length; i++) {
        if (script_elems[i].src.endsWith(script_name)) {
            var href = window.location.href;
            href = href.substring(0, href.lastIndexOf('/'));
            var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length);
            return url.substring(href.length+1, url.length);
        }
    }
    return '';
};

_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark
                                                   //the root directory of your library, any library.


_rmod.injectScript = function(script_name, uri, callback, prepare) {

    if(!prepare)
        prepare(script_name, uri);

    var script_elem = document.createElement('script');
    script_elem.type = 'text/javascript';
    script_elem.title = script_name;
    script_elem.src = uri;
    script_elem.async = true;
    script_elem.defer = false;

    if(!callback)
        script_elem.onload = function() {
            callback(script_name, uri);
        };
    document.getElementsByTagName('head')[0].appendChild(script_elem);
};

_rmod.requirePrepare = function(script_name, uri) {
    _rmod.loading.scripts[script_name] = uri;
    _rmod.loading.length++;
};

_rmod.requireCallback = function(script_name, uri) {
    _rmod.loading.length--;
    delete _rmod.loading.scripts[script_name];
    _rmod.imported[script_name] = uri;

    if(_rmod.loading.length == 0)
        _rmod.onReady();
};

_rmod.onReady = function() {
    if (!_rmod.LOADED) {
        for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){
            _rmod.on_ready_fn_stack[i]();
        });
        _rmod.LOADED = true;
    }
};

_.rmod = namespaceToUri = function(script_name, url) {
    var np = script_name.split('.');
    if (np.getLast() === '*') {
        np.pop();
        np.push('_all');
    }

    if(!url)
        url = '';

    script_name = np.join('.');
    return  url + np.join('/')+'.js';
};

//You can rename based on your liking. I chose require, but it
//can be called include or anything else that is easy for you
//to remember or write, except "import", because it is reserved
//for future use.
var require = function(script_name) {
    var uri = '';
    if (script_name.indexOf('/') > -1) {
        uri = script_name;
        var lastSlash = uri.lastIndexOf('/');
        script_name = uri.substring(lastSlash+1, uri.length);
    } 
    else {
        uri = _rmod.namespaceToUri(script_name, ivar._private.libpath);
    }

    if (!_rmod.loading.scripts.hasOwnProperty(script_name)
     && !_rmod.imported.hasOwnProperty(script_name)) {
        _rmod.injectScript(script_name, uri,
            _rmod.requireCallback,
                _rmod.requirePrepare);
    }
};

var ready = function(fn) {
    _rmod.on_ready_fn_stack.push(fn);
};

stamat

Posted 2009-06-04T11:59:50.987

Reputation: 939

10

My usual method is:

var require = function (src, cb) {
    cb = cb || function () {};

    var newScriptTag = document.createElement('script'),
        firstScriptTag = document.getElementsByTagName('script')[0];
    newScriptTag.src = src;
    newScriptTag.async = true;
    newScriptTag.onload = newScriptTag.onreadystatechange = function () {
        (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') && (cb());
    };
    firstScriptTag.parentNode.insertBefore(newScriptTag, firstScriptTag);
}

It works great and uses no page-reloads for me. I've tried the AJAX method (one of the other answers) but it doesn't seem to work as nicely for me.

Here's an explanation of how the code works for those that are curious: essentially, it creates a new script tag (after the first one) of the URL. It sets it to asynchronous mode so it doesn't block the rest of the code, but calls a callback when the readyState (the state of the content to be loaded) changes to 'loaded'.

Christopher Dumas

Posted 2009-06-04T11:59:50.987

Reputation: 763

9

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

Sam4Code

Posted 2009-06-04T11:59:50.987

Reputation: 313

2

This is the simplest code, but will fail in some edge cases when body doesn't yet exist or can't be modified. Also, it helps to explain answers.

– Dan Dascalescu – 2015-07-08T02:54:31.857

9

In modern language it would be

function loadJs( url ){
  return new Promise( resolve => {
    const script = document.createElement( "script" );
    script.src = url;
    script.onload = resolve;
    document.head.appendChild( script );
  });
}

Dmitry Sheiko

Posted 2009-06-04T11:59:50.987

Reputation: 992

8

This script will add a JavaScript file to the top of any other <script> tag:

(function () {
    var li = document.createElement('script'); 
    li.type = 'text/javascript'; 
    li.src= "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"; 
    li.async=true; 
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(li, s);
})();

Vicky Gonsalves

Posted 2009-06-04T11:59:50.987

Reputation: 8 450

8

There is also Head.js. It is very easy to deal with:

head.load("js/jquery.min.js",
          "js/jquery.someplugin.js",
          "js/jquery.someplugin.css", function() {
  alert("Everything is ok!");
});

As you see, it's easier than Require.js and as convenient as jQuery's $.getScript method. It also has some advanced features, like conditional loading, feature detection and much more.

Ale

Posted 2009-06-04T11:59:50.987

Reputation: 1 581

8

There are a lot of potential answers for this question. My answer is obviously based on a number of them. This is what I ended up with after reading through all the answers.

The problem with $.getScript and really any other solution that requires a callback when loading is complete is that if you have multiple files that use it and depend on each other you no longer have a way to know when all scripts have been loaded (once they are nested in multiple files).

Example:

file3.js

var f3obj = "file3";

// Define other stuff

file2.js:

var f2obj = "file2";
$.getScript("file3.js", function(){

    alert(f3obj);

    // Use anything defined in file3.
});

file1.js:

$.getScript("file2.js", function(){
    alert(f3obj); //This will probably fail because file3 is only guaranteed to have loaded inside the callback in file2.
    alert(f2obj);

    // Use anything defined in the loaded script...
});

You are right when you say that you could specify Ajax to run synchronously or use XMLHttpRequest, but the current trend appears to be to deprecate synchronous requests, so you may not get full browser support now or in the future.

You could try to use $.when to check an array of deferred objects, but now you are doing this in every file and file2 will be considered loaded as soon as the $.when is executed not when the callback is executed, so file1 still continues execution before file3 is loaded. This really still has the same problem.

I decided to go backwards instead of forwards. Thank you document.writeln. I know it's taboo, but as long as it is used correctly this works well. You end up with code that can be debugged easily, shows in the DOM correctly and can ensure the order the dependencies are loaded correctly.

You can of course use $ ("body").append(), but then you can no longer debug correctly any more.

NOTE: You must use this only while the page is loading, otherwise you get a blank screen. In other words, always place this before / outside of document.ready. I have not tested using this after the page is loaded in a click event or anything like that, but I am pretty sure it'll fail.

I liked the idea of extending jQuery, but obviously you don't need to.

Before calling document.writeln, it checks to make sure the script has not already been loading by evaluating all the script elements.

I assume that a script is not fully executed until its document.ready event has been executed. (I know using document.ready is not required, but many people use it, and handling this is a safeguard.)

When the additional files are loaded the document.ready callbacks will get executed in the wrong order. To address this when a script is actually loaded, the script that imported it is re-imported itself and execution halted. This causes the originating file to now have its document.ready callback executed after any from any scripts that it imports.

Instead of this approach you could attempt to modify the jQuery readyList, but this seemed like a worse solution.

Solution:

$.extend(true,
{
    import_js : function(scriptpath, reAddLast)
    {
        if (typeof reAddLast === "undefined" || reAddLast === null)
        {
            reAddLast = true; // Default this value to true. It is not used by the end user, only to facilitate recursion correctly.
        }

        var found = false;
        if (reAddLast == true) // If we are re-adding the originating script we do not care if it has already been added.
        {
            found = $('script').filter(function () {
                return ($(this).attr('src') == scriptpath);
            }).length != 0; // jQuery to check if the script already exists. (replace it with straight JavaScript if you don't like jQuery.
        }

        if (found == false) {

            var callingScriptPath = $('script').last().attr("src"); // Get the script that is currently loading. Again this creates a limitation where this should not be used in a button, and only before document.ready.

            document.writeln("<script type='text/javascript' src='" + scriptpath + "'></script>"); // Add the script to the document using writeln

            if (reAddLast)
            {
                $.import_js(callingScriptPath, false); // Call itself with the originating script to fix the order.
                throw 'Readding script to correct order: ' + scriptpath + ' < ' + callingScriptPath; // This halts execution of the originating script since it is getting reloaded. If you put a try / catch around the call to $.import_js you results will vary.
            }
            return true;
        }
        return false;
    }
});

Usage:

File3:

var f3obj = "file3";

// Define other stuff
$(function(){
    f3obj = "file3docready";
});

File2:

$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
    f2obj = "file2docready";
});

File1:

$.import_js('js/file2.js');

// Use objects from file2 or file3
alert(f3obj); // "file3"
alert(f2obj); // "file2"

$(function(){
    // Use objects from file2 or file3 some more.
    alert(f3obj); //"file3docready"
    alert(f2obj); //"file2docready"
});

curlyhairedgenius

Posted 2009-06-04T11:59:50.987

Reputation: 392

This is exactly what the currently accepted answer states: just not enough. – IamGuest – 2017-02-02T23:31:40.693

The main difference is that if there is a missing dependency it will add the script tag for the dependency, then also add the script tag for the calling file, and throw an error which halts execution. This causes the scripts to be processed and ran in the correct order and removes the need for callbacks. So the dependent script will be loaded and executed before the calling script while supporting nesting. – curlyhairedgenius – 2017-02-17T00:19:54.653

8

I came to this question because I was looking for a simple way to maintain a collection of useful JavaScript plugins. After seeing some of the solutions here, I came up with this:

  1. Set up a file called "plugins.js" (or extensions.js or what have you). Keep your plugin files together with that one master file.

  2. plugins.js will have an array called "pluginNames[]" that we will iterate over each(), then append a tag to the head for each plugin

    //set array to be updated when we add or remove plugin files var pluginNames = ["lettering", "fittext", "butterjam", etc.]; //one script tag for each plugin $.each(pluginNames, function(){ $('head').append(''); });

  3. manually call just the one file in your head:
    <script src="js/plugins/plugins.js"></script>

I found that even though all of the plugins were getting dropped into the head tag the way they ought to, they weren't always being run by the browser when you click into the page or refresh.

I found it's more reliable to just write the script tags in a PHP include. You only have to write it once and that's just as much work as calling the plugin using JavaScript.

rgb_life

Posted 2009-06-04T11:59:50.987

Reputation: 153

@will, your solution looks much cleaner than mine and I'm worried I might have some errors if I use mine, as it makes use of .append(). So to use this, you can just call that function once for each plugin file you wish to include? – rgb_life – 2011-12-01T05:55:18.587

7

I have created a function that will allow you to use similar verbiage to C#/Java to include a JavaScript file. I've tested it a little bit even from inside of another JavaScript file and it seems to work. It does require jQuery though for a bit of "magic" at the end.

I put this code in a file at the root of my script directory (I named it global.js, but you can use whatever you want. Unless I'm mistaken this and jQuery should be the only required scripts on a given page. Keep in mind this is largely untested beyond some basic usage, so there may or may not be any issues with the way I've done it; use at your own risk yadda yadda I am not responsible if you screw anything up yadda yadda:

/**
* @fileoverview This file stores global functions that are required by other libraries.
*/

if (typeof(jQuery) === 'undefined') {
    throw 'jQuery is required.';
}

/** Defines the base script directory that all .js files are assumed to be organized under. */
var BASE_DIR = 'js/';

/**
* Loads the specified file, outputting it to the <head> HTMLElement.
*
* This method mimics the use of using in C# or import in Java, allowing
* JavaScript files to "load" other JavaScript files that they depend on
* using a familiar syntax.
*
* This method assumes all scripts are under a directory at the root and will
* append the .js file extension automatically.
*
* @param {string} file A file path to load using C#/Java "dot" syntax.
*
* Example Usage:
* imports('core.utils.extensions');
* This will output: <script type="text/javascript" src="/js/core/utils/extensions.js"></script>
*/
function imports(file) {
    var fileName = file.substr(file.lastIndexOf('.') + 1, file.length);

    // Convert PascalCase name to underscore_separated_name
    var regex = new RegExp(/([A-Z])/g);
    if (regex.test(fileName)) {
        var separated = fileName.replace(regex, ",$1").replace(',', '');
        fileName = separated.replace(/[,]/g, '_');
    }

    // Remove the original JavaScript file name to replace with underscore version
    file = file.substr(0, file.lastIndexOf('.'));

    // Convert the dot syntax to directory syntax to actually load the file
    if (file.indexOf('.') > 0) {
        file = file.replace(/[.]/g, '/');
    }

    var src = BASE_DIR + file + '/' + fileName.toLowerCase() + '.js';
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;

    $('head').find('script:last').append(script);
}

Wayne Molina

Posted 2009-06-04T11:59:50.987

Reputation: 9 043

6

Better use the jQuery way. To delay the ready event, first call $.holdReady(true). Example (source):

$.holdReady(true);
$.getScript("myplugin.js", function() {
    $.holdReady(false);
});

weageoo

Posted 2009-06-04T11:59:50.987

Reputation: 77

The jQuery docs say that the callback passed to getScript will run "once the script has been loaded but not necessarily executed".

– Flimm – 2015-06-18T14:47:45.670

6

Here is a Grunt plugin allowing you to use @import "path/to/file.js"; syntax in any file including JavaScript files. It can be paired with uglify or watch or any other plugin.

It can be installed with npm install: https://npmjs.org/package/grunt-import

Marcin

Posted 2009-06-04T11:59:50.987

Reputation: 3 104

6

Here's a workaround for browsers (not Node.js) using HTML imports.

First, all JavaScript classes and scripts are not in .js files, but in .js.html files (the .js.html is just to recognize between HTML pages and complete JavaScript script/classes), inside <script> tags, like this:

MyClass.js.html:

<script>
   class MyClass {

      // Your code here..

   }

</script>

Then if you wish to import your class, you just need to use HTML imports:

<link rel="import" href="relative/path/to/MyClass.js.html"/>

<script>
   var myClass = new MyClass();
   // Your code here..
</script>

EDIT : HTML imports will be dropped

HTML imports and ES6 modules are both already well implemented in most browser accross the world. But since HTML imports are definitly not going to be part of the standards, unlike ES6 modules, its development will be dropped, then you should definitly start to use ES6 modules.

Yairopro

Posted 2009-06-04T11:59:50.987

Reputation: 1 438

6

Although these answers are great, there is a simple "solution" that has been around since script loading existed, and it will cover 99.999% of most people's use cases. Just include the script you need before the script that requires it. For most projects it does not take long to determine which scripts are needed and in what order.

<!DOCTYPE HTML>
<html>
    <head>
        <script src="script1.js"></script>
        <script src="script2.js"></script>
    </head>
    <body></body>
</html>

If script2 requires script1, this really is the absolute easiest way to do something like this. I'm very surprised no-one has brought this up, as it's the most obvious and simplest answer that will apply in nearly every single case.

KthProg

Posted 2009-06-04T11:59:50.987

Reputation: 911

6

There are several ways to implement modules in Javascript, Here are the 2 most popular ones:

ES6 Modules

Browsers do not support this moduling system yet so in order for you to use this syntax you must use a bundler like webpack. Using a bundler is better anyway because this can combine all of your different files into a single (or couple related) files. This will serve the files from the server to the client faster because each HTTP request has some associated overhead accompanied with it. Thus by reducing the overal HTTP request we improve the performance. Here is an example of ES6 modules:

// main.js file

export function add (a, b) {
  return a + b;
}

export default function multiply (a, b) {
  return a * b;
}


// test.js file

import {add}, multiply from './main';   // for named exports between curly braces {export1, export2}
                                        // for default exports without {}

console.log(multiply(2, 2));  // logs 4

console.log(add(1, 2));  // logs 3

CommonJS (used in NodeJS)

This moduling system is used in NodeJS. You basically add your exports to an object which is called module.exports. You then can access this object via a require('modulePath'). Important here is to realize that these modules are being cached, so if you require() a certain module twice it will return the already created module.

// main.js file

function add (a, b) {
  return a + b;
}

module.exports = add;  // here we add our add function to the exports object


// test.js file

const add = require('./main'); 

console.log(add(1,2));  // logs 3

Willem van der Veen

Posted 2009-06-04T11:59:50.987

Reputation: 3 840

5

Keep it nice, short, simple, and maintainable! :]

// 3rd party plugins / script (don't forget the full path is necessary)
var FULL_PATH = '', s =
[
    FULL_PATH + 'plugins/script.js'      // Script example
    FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library 
    FULL_PATH + 'plugins/crypto-js/hmac-sha1.js',      // CryptoJS
    FULL_PATH + 'plugins/crypto-js/enc-base64-min.js'  // CryptoJS
];

function load(url)
{
    var ajax = new XMLHttpRequest();
    ajax.open('GET', url, false);
    ajax.onreadystatechange = function ()
    {
        var script = ajax.response || ajax.responseText;
        if (ajax.readyState === 4)
        {
            switch(ajax.status)
            {
                case 200:
                    eval.apply( window, [script] );
                    console.log("library loaded: ", url);
                    break;
                default:
                    console.log("ERROR: library not loaded: ", url);
            }
        }
    };
    ajax.send(null);
}

 // initialize a single load 
load('plugins/script.js');

// initialize a full load of scripts
if (s.length > 0)
{
    for (i = 0; i < s.length; i++)
    {
        load(s[i]);
    }
}

This code is simply a short functional example that could require additional feature functionality for full support on any (or given) platform.

tfont

Posted 2009-06-04T11:59:50.987

Reputation: 6 486

5

I basically do it like the following, creating a new element and attach that to head:

var x = document.createElement('script');
x.src = 'http://example.com/test.js';
document.getElementsByTagName("head")[0].appendChild(x);

In jQuery:

// jQuery
$.getScript('/path/to/imported/script.js', function()
{
    // Script is now loaded and executed.
    // Put your dependent JavaScript code here.
});

Rahul Srivastava

Posted 2009-06-04T11:59:50.987

Reputation: 102

5

For NodeJS only, This worked for me the best!

I've tried most solutions here, but none helped me about just being able to load another file without changing scope. Finally I used this. Which preserves the scope and everything. It is as good as your code is in that point.

const fs = require('fs');
eval(fs.readFileSync('file.js')+'');

rturkek

Posted 2009-06-04T11:59:50.987

Reputation: 380

4

I have the requirement to asynchronously load an array of JavaScript files and at the final make a callback. Basically my best approach is the following:

// Load a JavaScript file from other JavaScript file
function loadScript(urlPack, callback) {
    var url = urlPack.shift();
    var subCallback;

    if (urlPack.length == 0) subCallback = callback;
    else subCallback = function () {
        console.log("Log script: " + new Date().getTime());
        loadScript(urlPack, callback);
    }

    // Adding the script tag to the head as suggested before
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = subCallback;
    script.onload = subCallback;

    // Fire the loading
    head.appendChild(script);
}

Example:

loadScript(
[
    "js/DataTable/jquery.dataTables.js",
    "js/DataTable/dataTables.bootstrap.js",
    "js/DataTable/dataTables.buttons.min.js",
    "js/DataTable/dataTables.colReorder.min.js",
    "js/DataTable/dataTables.fixedHeader.min.js",
    "js/DataTable/buttons.bootstrap.min.js",
    "js/DataTable/buttons.colVis.min.js",
    "js/DataTable/buttons.html5.min.js"
], function() { gpLoad(params); });

The second script will not load until the first is completely loaded, and so...

Results:

Result

MiBol

Posted 2009-06-04T11:59:50.987

Reputation: 730

4

If you use Angular, then a plugin module $ocLazyLoad can help you to do that.

Here are some quotes from its documentation:

Load one or more modules & components with multiple files:

$ocLazyLoad.load(['testModule.js', 'testModuleCtrl.js', 'testModuleService.js']);

Load one or more modules with multiple files and specify a type where necessary: Note: When using the requireJS style formatting (with js! at the beginning for example), do not specify a file extension. Use one or the other.

$ocLazyLoad.load([
  'testModule.js',
   {type: 'css', path: 'testModuleCtrl'},
   {type: 'html', path: 'testModuleCtrl.html'},
   {type: 'js', path: 'testModuleCtrl'},
   'js!testModuleService',
   'less!testModuleLessFile'
]);

You can load external libs (not angular):

$ocLazyLoad.load(['testModule.js', 
   'bower_components/bootstrap/dist/js/bootstrap.js', 'anotherModule.js']);

You can also load css and template files:

 $ocLazyLoad.load([
     'bower_components/bootstrap/dist/js/bootstrap.js',
     'bower_components/bootstrap/dist/css/bootstrap.css',
     'partials/template1.html'
 ]);

gm2008

Posted 2009-06-04T11:59:50.987

Reputation: 2 871

4

It's very simple. Suppose you want to import file A.js in file B.js.

Now it's sure you have linked B.js in an HTML file, then just link A.js before B.js in that HTML file. Then the public variables of A.js will be available inside the B.js

This does not require a complicated answer.

Akshay Vijay Jain

Posted 2009-06-04T11:59:50.987

Reputation: 2 011

3

Don't forget to check out LAB.js!

<script type="text/javascript">
       $LAB
       .script("jquery-1.8.3.js").wait()
       .script("scripts/clientscript.js");      
</script>

emolaus

Posted 2009-06-04T11:59:50.987

Reputation: 496

2

Unfortunately, it's not really under development any more, and there's no guarantee that some future browser or JS engine or language version won't break it. You should try to be as up-to-date as possible with JS, although there is something to be said for stability. Even though this could be a good option for somebody, I'd much rather steer them toward RequireJS or jQuery.getScript(), both of which are stable and under constant development.

– MattDMo – 2013-06-01T18:02:11.713

3

Now, I may be totally misguided, but here's what I've recently started doing... Start and end your JavaScript files with a carriage return, place in the PHP script, followed by one more carriage return. The JavaScript comment "//" is ignored by PHP so the inclusion happens anyway. The purpose for the carriage returns is so that the first line of your included JavaScript isn't commented out.

Technically, you don't need the comment, but it posts errors in Dreamweaver that annoy me. If you're scripting in an IDE that doesn't post errors, you shouldn't need the comment or the carriage returns.

\n
//<?php require_once("path/to/javascript/dependency.js"); ?>

function myFunction(){
    // stuff
}
\n

Duncan

Posted 2009-06-04T11:59:50.987

Reputation: 1 292

3

var s=["Hscript.js","checkRobert.js","Hscript.js"];
for(i=0;i<s.length;i++){
  var script=document.createElement("script");
  script.type="text/javascript";
  script.src=s[i];
  document.getElementsByTagName("head")[0].appendChild(script)
};

robert

Posted 2009-06-04T11:59:50.987

Reputation: 105

3

Import and export modules using ES6 that work with Node.js

Name files with .mjs extension instead of .js

Create files

touch main.mjs lib.mjs

main.js

import { add } from './lib.mjs';
console.log(add(40, 2));

lib.mjs

export let add = (x,y) => {
  return x + y
}

Run

node --experimental-modules main.js

jasonleonhard

Posted 2009-06-04T11:59:50.987

Reputation: 1 658

3

In a past project I had quite a bit of success using ajile to do imports of reusable JavaScript files. I always wished there was a feature for this built into JavaScript itself.

jpierson

Posted 2009-06-04T11:59:50.987

Reputation: 8 485

2

You can't import, but you can reference.

PhpShtorm IDE. To reference, in one .js file to another .js, just add this to the top of the file:

<reference path="../js/file.js" />

Of course, you should use your own PATH to the JavaScript file.

I don't know if it will work in other IDEs. Probably yes, just try. It should work in Visual Studio too.

Evgeniy Miroshnichenko

Posted 2009-06-04T11:59:50.987

Reputation: 416

2

Here is maybe another way! In Node.js you do that just like the following! http://requirejs.org/docs/node.html

sub.js

module.exports = {
  log: function(string) {
    if(console) console.log(string);
  }
  mylog: function(){
    console.log('just for log test!');
  }
}

main.js

var mylog =require('./sub');

mylog.log('Hurray, it works! :)');
mylog.mylog();

xgqfrms

Posted 2009-06-04T11:59:50.987

Reputation: 2 426

2

Another approach is to use HTML imports. These can contain script references as well as stylesheet references.

You can just link an HTML file like

<link rel="import" href="vendorScripts.html"/>

Within the vendorScripts.html file you can include your script references like:

<script src="scripts/vendors/jquery.js"></script>
<script src="scripts/vendors/bootstrap.js"></script>
<script src="scripts/vendors/angular.js"></script>
<script src="scripts/vendors/angular-route.js"></script>

Look at HTML Imports for more details.

Unfortunately this only works in Chrome.

gabriel211

Posted 2009-06-04T11:59:50.987

Reputation: 41

2

Yes, there is...

Keep reading, in ES6, we can export and import part or whole javascript file into another one...

But wait, ES6 is not supported in all the browsers, so what you need is transpile it using babel.js for example...

So you create a class like below:

class Person {
  constructor(name) {
    this.name = name;
  }

  build() {
    return new Person(this);
  }
}

module.exports = Person;

in Another JavaScript file, do the import like:

import { Person } from 'Person';

You also can require the file like:

const Person = require('./Person');

If you are using older JavaScript version you can use requirejs:

requirejs(["helper/util"], function(util) {
    //This function is called when scripts/helper/util.js is loaded.
    //If util.js calls define(), then this function is not fired until
    //util's dependencies have loaded, and the util argument will hold
    //the module value for "helper/util".
});

If you want to stick to older version of stuffs, like jQuery, you can also use something like getScript:

jQuery.getScript('./another-script.js', function() {
    // Call back after another-script loaded
});

Last but not the least, don't forget you can do the traditional way of putting script together using <script> tag...

<script src="./first-script.js"></script>
<script src="./second-script.js"></script>
<script src="./third-script.js"></script>

There are also async and defer attribute which I should mention them here...

Note: There are several ways an external script can be executed:

  • If async is present: The script is executed asynchronously with the rest of the page (the script will be executed while the page continues the parsing)
  • If async is not present and defer is present: The script is executed when the page has finished parsing
  • If neither async or defer is present: The script is fetched and executed immediately, before the browser continues parsing the page

Alireza

Posted 2009-06-04T11:59:50.987

Reputation: 43 514

0

var xxx = require("../lib/your-library.js")

or

import xxx from "../lib/your-library.js" //get default export
import {specificPart} from '../lib/your-library.js' //get named export
import * as _name from '../lib/your-library.js'  //get full export to alias _name

Mesut Yiğit

Posted 2009-06-04T11:59:50.987

Reputation: 415

0

If you find there are 2 or more scripts occupied the same function when they are called, then we cannot be included them in the same times, we need to do it dynamically by user selection.

Including another files in jQuery using $.getScript works since the script will not be cached by default. So we are save to call another scripts. The calls can be arranged like this:

HTML

<select class="choice">
  <option value="script1" selected>Script-1</option>
  <option value="script2">Script-2</option>
</select>

JS

  $(".choice").change(on_change);

    var url = "https://example.com";
    $.url1 = url + "/script1.js";
    $.url2 = url + "/script2.js";

  function on_change() {
    if ($(".choice").val()=="script1") {
        script1();
    } else {
        script2();
    }

    // script1
    function script1() {   
      $.getScript($.url1, function( data, textStatus, jqxhr ) {
          //excecute here
      });  
    }

    // script2
    function script2() {
       $.getScript($.url2, function( data, textStatus, jqxhr ) {
          //excecute here
      });  
    }

Chetabahana

Posted 2009-06-04T11:59:50.987

Reputation: 3 301

-1

Please note that we usually use static scripts. So we want to be taken from the cache as much as possible. This saves network traffic and speeds up landing.

Usage

$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {
  console.log( textStatus );
});

cache: true option has been added to the ajax method

Adam111p

Posted 2009-06-04T11:59:50.987

Reputation: 1 413

-3

function include(js)
{
    document.writeln("<script src=" + js + "><" + "/script>");
}

Amir Saniyan

Posted 2009-06-04T11:59:50.987

Reputation: 5 124

Why was this downvoted? I'm no JS expert, but wouldn't this work? – Gottlieb Notschnabel – 2013-10-20T11:35:51.033

6Because if the page is already done loading when it is executing, or if it is executed because of a user action, then it will clear the page first. – SevenBits – 2013-10-20T11:56:00.567

1

@SevenBits is correct and this answer is buggy, see this page: https://developer.mozilla.org/en-US/docs/Web/API/Document/write

– Flimm – 2015-06-18T14:52:22.003

@Flimm you could have linked to the page on writeln instead, but it's basically the same. – gcampbell – 2016-06-22T19:21:27.840