javascript теги - Как включить файл JavaScript в другой файл JavaScript?




15 Answers

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

Но с 2015 года (ES6) у JavaScript был стандарт ES6 для импорта модулей в Node.js, который также поддерживается большинством современных браузеров .

Для совместимости со старыми браузерами можно использовать инструменты build и / или transpilation .

Модули ES6

Модули ECMAScript (ES6) поддерживаются в Node.js с v8.5 с --experimental-modules . Все файлы должны иметь расширение .mjs .

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

Модули ECMAScript в браузерах

Браузеры поддерживали загрузку модулей ECMAScript напрямую (таких инструментов как Webpack не требуется), since Safari 10.1, Chrome 61, Firefox 60 и Edge 16. Проверьте текущую поддержку на 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);
}

Читайте больше на: since

Динамический импорт в браузерах

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

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

Подробнее читайте на https://developers.google.com/web/updates/2017/11/dynamic-import

Node.js требует

Старый стиль импорта модулей, все еще широко используемый в Node.js, является системой module.exports/require .

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

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

Оба этих решения обсуждаются и проиллюстрированы в JavaScript Madness: Dynamic Script Loading .

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

Теперь есть большая проблема, о которой вы должны знать. Это означает, что вы дистанционно загружаете код . Современные веб-браузеры загружают файл и продолжают выполнять ваш текущий скрипт, потому что они загружают все асинхронно, чтобы повысить производительность. (Это относится как к методу 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 в целом, которая обсуждает это.

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

Как упоминалось в начале этого ответа, многие разработчики используют в своих проектах инструменты (средства) для сборки / транспиляции, такие как Parcel, Webpack или Babel, позволяя им использовать будущий синтаксис JavaScript, обеспечивать обратную совместимость для старых браузеров, комбинировать файлы, выполнять разделение кода и т. д.

вызов подгрузка

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




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

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

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

Однако этот метод также имеет проблему: если в импортированном файле JavaScript произошла ошибка, Firebug (а также 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');

Я также сделал простой Example этого Example .

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

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

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

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




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

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

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

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




import находится в ECMAScript 6.

Синтаксис

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;



Вот синхронная версия без 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);
}

Обратите внимание, что для получения этого рабочего кросс-домена серверу необходимо будет установить заголовок allow-origin в своем ответе.




Вот обобщенная версия того, как Facebook делает это для своей вездесущей кнопки Like:

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

Если он работает в Facebook, он будет работать на вас.

Причина, по которой мы ищем первый элемент script вместо head или body заключается в том, что некоторые браузеры не создают одного, если не хватает, но у нас гарантированно есть элемент script - этот. Подробнее читайте на http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/ .




Большинство приведенных здесь решений подразумевают динамическую загрузку. Я искал вместо этого компилятор, который собирал все зависящие файлы в один выходной файл. То же, что и препроцессоры Less / Sass @import с CSS @import at-rule. Поскольку я не нашел ничего подходящего в этом роде, я написал простой инструмент для решения проблемы.

Итак, вот компилятор https://github.com/dsheiko/jsic , который надежно заменяет $import("file-path") запрошенным файлом. Вот соответствующий плагин Grunt : https://github.com/dsheiko/grunt-jsic .

На главной ветви jQuery они просто объединяют файлы исходного кода в один, начиная с intro.js и заканчивая outtro.js . Это меня не устраивает, поскольку он не обеспечивает гибкости при разработке исходного кода. Посмотрите, как это работает с jsic:

SRC / main.js

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

ЦСИ / Форма / вход / Tel.js

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

Теперь мы можем запустить компилятор:

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

И получить объединенный файл

строить / main.js

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



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

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

Вам просто нужно быть осторожным, когда вы включаете скрипты в файл HTML. Порядок должен быть следующим:

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



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

Я использую Sprockets (я не знаю, есть ли другие). Вы создаете свой код JavaScript в отдельных файлах и включаете комментарии, которые обрабатываются движком Sprockets, в том числе. Для разработки вы можете включать файлы последовательно, затем для их слияния ...

Смотрите также:




У меня была простая проблема, но я был озадачен ответами на этот вопрос.

Мне пришлось использовать переменную (myVar1), определенную в одном файле JavaScript (myvariables.js) в другом файле JavaScript (main.js).

Для этого я сделал следующее:

Загрузите код JavaScript в файл HTML в правильном порядке, сначала myvariables.js, затем main.js:

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

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

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

Файл: myvariables.js

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

Файл: main.js

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

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

Это спасло мой день. Надеюсь, это поможет.




Я написал простой модуль, который автоматизирует работу по импорту / включая скрипты модулей в JavaScript. Подробное объяснение кода см. В блоге, в котором должны быть указаны модули require / import / include .

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



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

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

document.body.appendChild(js);



Этот скрипт добавит файл JavaScript в начало любого другого <script>тега:

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



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

  1. Настройте файл под названием «plugins.js» (или extensions.js или что у вас есть). Храните файлы плагинов вместе с одним основным файлом.

  2. plugins.js будет иметь массив под названием «pluginNames []», который мы будем перебирать по каждому (), а затем добавим тег в голову для каждого плагина

    // устанавливаем массив для обновления при добавлении или удалении файлов плагинов var pluginNames = ["надпись", "fittext", "butterjam" и т. д.]; // один тег скрипта для каждого плагина $ .each (pluginNames, function () {$ ('head'). append ('');});

  3. вручную вызовите только один файл в голове:
    <script src="js/plugins/plugins.js"></script>

Я обнаружил, что, несмотря на то, что все плагины попадают в заголовок так, как им следовало бы, они не всегда запускались браузером при нажатии на страницу или обновлении.

Я обнаружил, что более надежно просто писать теги скриптов в PHP include. Вам нужно только написать его один раз, и это так же много работает, как вызвать плагин с использованием JavaScript.




Я создал функцию, которая позволит вам использовать схожие формулировки с C # / Java для включения файла JavaScript. Я тестировал его немного даже изнутри другого файла JavaScript и, похоже, работает. Это требует jQuery, хотя для немного «магии» в конце.

Я поместил этот код в файл в корень моего каталога сценариев (я его назвал global.js, но вы можете использовать все, что захотите. Если я не ошибаюсь, это и jQuery должны быть единственными необходимыми сценариями на данной странице. в значительной степени непроверен за пределами некоторого базового использования, поэтому могут быть или не быть какие-либо проблемы с тем, как я это сделал, использовать на свой страх и риск yadda yadda Я не несу ответственности, если вы ввернете что-нибудь в 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);
}



Related

javascript file import include