Вопрос: Как включить файл JavaScript в другой файл JavaScript?


Есть ли что-то в JavaScript, похожее на @importв CSS, который позволяет вам включать файл JavaScript в другой файл JavaScript?


4055


источник


Ответы:


Старые версии JavaScript не импортировали, не включали и не требовали, так много разных подходов к этой проблеме были разработаны.

Но последние версии JavaScript имеют такие стандарты, как Модули ES6 для импорта модулей, хотя большинство браузеров это еще не поддерживается. Многие люди, использующие модули с приложениями в браузере, используют строить и / или transpilation чтобы сделать его практичным для использования нового синтаксиса с такими функциями, как модули.

Модули ES6

Обратите внимание, что в настоящее время поддержка браузера для модулей ES6 не особенно велика, но она уже в пути. В соответствии с этот ответ StackOverflow , они поддерживаются в Chrome 61, Firefox 54 (за dom.moduleScripts.enabledустановка в about:config) и MS Edge 16, только Safari 10.1 обеспечивает поддержку без флагов.

Таким образом, в настоящее время вам все еще нужно будет использовать инструменты сборки и / или трансляции для действительного JavaScript, который будет работать без каких-либо требований для использования этими версиями браузера или включения любых флагов.

Как только ES6-модули являются обычным явлением, вот как вы могли бы использовать их:

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

Node.js требует

Node.js в настоящее время использует module.exports / требуют система. Вы можете использовать babelперевести, если вы хотите importсинтаксис.

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

Существуют и другие способы включения JavaScript в JavaScript для браузеров, которые не требуют предварительной обработки.

Загрузка AJAX

Вы можете загрузить дополнительный скрипт с вызовом AJAX, а затем использовать evalдля запуска. Это самый простой способ, но он ограничен вашим доменом из-за модели безопасности песочницы JavaScript. С помощью evalтакже открывает дверь к ошибкам, хакам и проблемам безопасности.

Загрузка jQuery

JQuery библиотека обеспечивает функциональность загрузки в одной строке :

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

Загрузка динамического скрипта

Вы можете добавить тег скрипта с URL-адресом сценария в HTML. Чтобы избежать накладных расходов на jQuery, это идеальное решение.

Сценарий может находиться на другом сервере. Кроме того, браузер оценивает код. <script>тег можно вставить на веб-страницу <head>, или вставлен непосредственно перед закрытием </body>тег.

Вот пример того, как это может работать:

function dynamicallyLoadScript(url) {
    var script = document.createElement("script"); // Make a script DOM node
    script.src = url; // Set it's 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)
}

Эта функция добавит новую <script>тег до конца главы раздела страницы, где srcатрибуту присваивается URL-адрес, который присваивается функции в качестве первого параметра.

Оба этих решения обсуждаются и проиллюстрированы в Безумие JavaScript: загрузка динамического скрипта ,

Обнаружение при выполнении сценария

Теперь есть большая проблема, о которой вы должны знать. Это означает, что вы дистанционно загружаете код , Современные веб-браузеры загружают файл и продолжают выполнять ваш текущий скрипт, потому что они загружают все асинхронно, чтобы повысить производительность. (Это относится как к методу jQuery, так и к способу загрузки ручного динамического сценария.)

Это означает, что если вы используете эти трюки напрямую, вы не сможете использовать свой новый загруженный код на следующей строке после того, как вы попросите его загрузить , потому что он будет по-прежнему загружаться.

Например: my_lovely_script.jsсодержит 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

Затем вы перезагружаете страницу F5 , И это работает! Смешение ...

Так что с этим делать?

Хорошо, вы можете использовать взломанный автор в ссылке, которую я вам дал. Итак, для людей, которые спешат, он использует событие для запуска функции обратного вызова при загрузке сценария. Таким образом, вы можете поместить весь код с помощью удаленной библиотеки в функцию обратного вызова. Например:

function loadScript(url, 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 = callback;
    script.onload = callback;

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

Затем вы пишете код, который хотите использовать ПОСЛЕ того, как скрипт загружается в лямбда-функция :

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

Тогда вы запустите все это:

loadScript("my_lovely_script.js", myPrettyCode);

Обратите внимание, что сценарий может выполняться после загрузки DOM или раньше, в зависимости от браузера, и включил ли вы линию script.async = false;, Есть отличная статья о загрузке Javascript в целом в котором обсуждается это.

Слияние / предварительная обработка исходного кода

Как уже упоминалось в начале этого ответа, многие разработчики теперь используют в своих проектах инструменты (средства) для создания / транспиляции, такие как WebPack, Babel или Gulp, что позволяет им лучше использовать новые модули синтаксиса и поддержки, объединять файлы, минимизировать и т. Д.


3498



Если кто-то ищет что-то более продвинутое, попробуйте RequireJS , Вы получите дополнительные преимущества, такие как управление зависимостями, лучший параллелизм и избегайте дублирования (т. Е. Извлекаете сценарий несколько раз).

Вы можете писать свои файлы JavaScript в «modules», а затем ссылаться на них как на зависимости в других сценариях. Или вы можете использовать RequireJS как простое решение «get get this script».

Пример:

Определить зависимости как модули:

некоторые-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 является вашим «основным» файлом JavaScript, который зависит от некоторые-dependency.js

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

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

Выдержка из GitHub ПРОЧТИ МЕНЯ:

RequireJS загружает простые файлы JavaScript, а также более определенные   модули. Он оптимизирован для использования в браузере, в том числе в Интернете   Worker, но он может использоваться в других средах JavaScript, например   Rhino и Node. Он реализует API асинхронного модуля.

RequireJS использует теги простого сценария для загрузки модулей / файлов, поэтому он должен   позволяют легко отлаживать. Его можно просто использовать для загрузки существующих   Файлы JavaScript, поэтому вы можете добавить его в свой существующий проект без   переписывая ваши файлы JavaScript.

...


507



На самом деле является способ загрузки файла JavaScript не асинхронно, поэтому вы можете использовать функции, включенные в ваш загруженный файл, сразу после его загрузки, и я думаю, что он работает во всех браузерах.

Вы должны использовать jQuery.append()на <head>элемент вашей страницы, то есть:

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

Однако этот метод также имеет проблему: если в импортированном файле JavaScript произошла ошибка, поджигатель (а также Firefox Error Console и Инструменты разработчика Chrome также) сообщит о своем месте неправильно, что является большой проблемой, если вы используете Firebug для отслеживания ошибок JavaScript много (я). По какой-то причине Firebug просто не знает о недавно загруженном файле, поэтому, если в этом файле произошла ошибка, он сообщает, что это произошло в вашей основной HTML файл, и вам не удастся выяснить истинную причину ошибки.

Но если это не проблема для вас, тогда этот метод должен работать.

Я на самом деле написал плагин jQuery, называемый $ .import_js () который использует этот метод:

(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);

Итак, все, что вам нужно будет сделать для импорта JavaScript:

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

Я также сделал простой тест для этого на пример ,

Он включает main.jsфайл в основном HTML, а затем скрипт в main.jsиспользования $.import_js()для импорта дополнительного файла, называемого included.js, который определяет эту функцию:

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

И сразу после включения included.js, hello()вызывается функция, и вы получаете предупреждение.

(Этот ответ отвечает на комментарий e-satis).


158



Другой способ, который, на мой взгляд, намного чище, состоит в том, чтобы сделать синхронный запрос Ajax вместо использования <script>тег. Что также Node.js ручками.

Вот пример использования 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);
        }
    });
}

Затем вы можете использовать его в своем коде, как обычно, используйте include:

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

И иметь возможность вызывать функцию из требуемого скрипта в следующей строке:

subscript.doSomethingCool(); 

131



Для вас есть хорошая новость. Очень скоро вы сможете легко загрузить код JavaScript. Он станет стандартным способом импорта модулей кода JavaScript и будет частью самого основного JavaScript.

Вам просто нужно написать import cond from 'cond.js';для загрузки макроса с именем condиз файла cond.js,

Таким образом, вам не нужно полагаться на какие-либо рамки JavaScript, и вам не нужно явно указывать Ajax звонки.

Ссылаться на:


85



Возможно динамическое создание тега JavaScript и добавление его в HTML-документ из другого кода JavaScript. Это загрузит целевой файл JavaScript.

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");

71



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;

58



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

47



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.


46



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.


41



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


33



This is perhaps the biggest weakness of JavaScript in my opinion. It's caused me no end of problems over the years with dependency tracing. Anyhow, it does appear that the only practical solution is to use script includes in the HTML file and thus horribly making your JavaScript code dependent upon the user including the source you need and making reuse unfriendly.

Sorry if this comes across as a lecture ;) It's a (bad) habit of mine, but I want to make this point.

The problem comes back to the same as everything else with the web, the history of JavaScript. It really wasn't designed to be used in the widespread manner it's used in today. Netscape made a language that would allow you to control a few things, but they didn't envisage its widespread use for so many things as it is put to now and for one reason or another it's expanded from there, without addressing some of the fundamental weaknesses of the original strategy.

It's not alone of course. HTML wasn't designed for the modern webpage; it was designed to be a way of expressing the logic of a document, so that readers (browsers in the modern world) could display this in an applicable form that was within the capabilities of the system, and it took years for a solution (other than the hacks of MS and Netscape) to come along. CSS solves this problem, but it was a long time coming and even longer to get people to use it rather than the established BAD techniques. It happened though, praise be.

Hopefully JavaScript (especially now it's part of the standard) will develop to take on board the concept of proper modularity (as well as some other things) as every other (extant) programming language in the world does and this stupidity will go away. Until then you just have to not like it and lump it, I'm afraid.


30