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

5847
Alec Smart 4 Июн 2009 в 15:59

29 ответов

Лучший ответ

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

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

Для совместимости со старыми браузерами создайте такие инструменты, как Webpack и накопительный пакет и / или инструменты переноса, такие как Babel.

ES6 Модули

Модули ECMAScript (ES6) поддерживаются в Node.js начиная с версии 8.5, с {{ X0}} флаг, и, по крайней мере, Node.js v13.8.0 без флага. Чтобы включить «ESM» (по сравнению с предыдущей системой модулей CommonJS в стиле Node.js [«CJS»]), вы либо используете "type": "module" в package.json, либо даете файлам расширение .mjs. (Аналогично, модули, написанные с помощью предыдущего модуля CJS Node.js, могут называться .cjs, если по умолчанию используется ESM.)

Используя package.json:

{
    "type": "module"
}

Тогда module.js:

export function hello() {
  return "Hello";
}

Тогда main.js:

import { hello } from './module.js';
let val = hello();  // val is "Hello";

Используя .mjs, вы получите module.mjs:

export function hello() {
  return "Hello";
}

Тогда main.mjs:

import { hello } from './module.mjs';
let val = hello();  // val is "Hello";

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

Браузеры поддерживают загрузку модулей ECMAScript напрямую (не требуются такие инструменты, как Webpack) с тех пор Safari 10.1, Chrome 61, Firefox 60 и Edge 16. Проверьте текущую поддержку по адресу caniuse. , Нет необходимости использовать расширение .mjs Node.js; браузеры полностью игнорируют расширения файлов в модулях / скриптах.

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

Узнайте больше на https://jakearchibald.com/2017/es-modules-in-browsers /

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

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

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

Подробнее читайте в https://developers.google.com/web/updates/ 2017/11 / динамического импорта

Node.js требует

Более старый стиль модуля CJS, который до сих пор широко используется в Node.js, это module.exports / {{X1 }} система.

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

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

AJAX Загрузка

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

Загрузка Загрузка

Как и в случае динамического импорта, вы можете загрузить один или несколько сценариев с помощью вызова fetch, используя обещания для управления порядком выполнения зависимостей сценариев, используя Fetch Inject:

fetchInject([
  'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js'
]).then(() => {
  console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`)
})

Загрузка jQuery

Библиотека jQuery обеспечивает загрузку в одну строку:

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

Динамическая загрузка скриптов

Вы можете добавить тег HTML с 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: динамическая загрузка скриптов.

Обнаружение, когда скрипт был выполнен

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

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

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

Затем вы запускаете все это:

loadScript("my_lovely_script.js", myPrettyCode);

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

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

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

4408
T.J. Crowder 21 Мар 2020 в 09:09

Другой способ, который, на мой взгляд, намного чище, - это сделать синхронный 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(); 
154
Peter Mortensen 28 Сен 2013 в 12:55

Если вы используете веб-работников и хотите включить дополнительные сценарии в области работника, другие ответы о добавлении сценариев в тег head и т. д. не будут работать для вас.

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

В качестве альтернативы, в качестве второго наиболее высоко оцененного ответа на ваш вопрос выделяет, RequireJS также может обрабатывать включая скрипты внутри Web Worker (вероятно, вызывающего сам importScripts, но с несколькими другими полезными функциями).

16
Community 23 Май 2017 в 12:34

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

Мне пришлось использовать переменную (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 автоматически.

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

17
Peter Mortensen 11 Дек 2016 в 09:45

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

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

Примере:

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

< Сильный > некоторые - 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
});

creation.js - это ваш "основной" файл JavaScript, который зависит от some-dependency.js

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

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

Выдержка из GitHub README:

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

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

...

565
Peter Mortensen 28 Сен 2013 в 13:11

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

53
Flimm 18 Июн 2015 в 14:44

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

// ----- 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);
};
12
Peter Mortensen 19 Окт 2014 в 18:26
var js = document.createElement("script");

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

document.body.appendChild(js);
12
Spudley 22 Авг 2012 в 06:44

Это должно сделать:

xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
21
Peter Mortensen 2 Ноя 2014 в 13:50

Существует несколько способов реализации модулей в Javascript. Вот два наиболее популярных из них:

Модули ES6

Браузеры пока не поддерживают эту систему модуляции, поэтому для использования этого синтаксиса вы должны использовать такой пакет, как webpack. В любом случае лучше использовать упаковщик, потому что он может объединить все ваши разные файлы в один (или пару связанных) файлов. Это позволит быстрее передавать файлы с сервера на клиент, поскольку с каждым HTTP-запросом связаны некоторые накладные расходы. Таким образом, уменьшая общий HTTP-запрос, мы улучшаем производительность. Вот пример модулей ES6:

// 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 (используется в NodeJS)

Эта система модуляции используется в NodeJS. Вы в основном добавляете свои экспорты к объекту, который называется module.exports. Затем вы можете получить доступ к этому объекту через require('modulePath'). Важно понимать, что эти модули кэшируются, поэтому, если вы require() дважды определите модуль, он вернет уже созданный модуль.

// 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
10
Willem van der Veen 10 Авг 2018 в 17:11

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

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

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

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

100
Peter Mortensen 19 Окт 2014 в 18:05

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

<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, заключается в том, что некоторые браузеры не создают его в случае его отсутствия, но мы обязательно получим {{X3 }} элемент - этот. Узнайте больше на http://www.jspatterns.com/the-ridiculous- случай- из - добавления - а- скрипт - элемент /.

43
Dan Dascalescu 8 Июл 2015 в 02:48

Если вы хотите использовать чистый JavaScript, вы можете использовать document.write.

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

Если вы используете библиотеку jQuery, вы можете использовать метод $.getScript.

$.getScript("another_script.js");
37
K.Dᴀᴠɪs 30 Мар 2018 в 21:20

Если вы намерены загрузить файл 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>
25
Peter Mortensen 11 Дек 2016 в 09:42

Существует также Head.js. Это очень легко иметь дело с:

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

Как видите, это проще, чем Require.js, и так же удобно, как метод $.getScript jQuery. Он также имеет некоторые расширенные функции, такие как условная загрузка, обнаружение функций и гораздо больше.

10
Peter Mortensen 19 Окт 2014 в 18:18

Есть много потенциальных ответов на этот вопрос. Мой ответ, очевидно, основан на ряде из них. Это то, чем я закончил, прочитав все ответы.

Проблема с $.getScript и действительно любым другим решением, которое требует обратного вызова при завершении загрузки, состоит в том, что если у вас есть несколько файлов, которые используют его и зависят друг от друга, у вас больше нет способа узнать, когда все сценарии были загружены (как только они вложены в несколько файлов).

Примере:

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

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

Вы можете попытаться использовать $.when для проверки массива отложенных объектов, но теперь вы делаете это в каждом файле, и file2 будет считаться загруженным, как только будет выполнен $.when, а не при выполнении обратного вызова , так что file1 все еще продолжает выполнение до загрузки file3. Это действительно до сих пор та же проблема.

Я решил идти назад, а не вперед. Спасибо document.writeln. Я знаю, что это табу, но при правильном использовании это работает хорошо. Вы получите код, который можно легко отладить, правильно отобразить в DOM и убедиться, что зависимости загружены правильно.

Конечно, вы можете использовать $ ("body"). Append (), но тогда вы больше не сможете правильно отлаживать.

ПРИМЕЧАНИЕ. Вы должны использовать это только во время загрузки страницы, иначе вы получите пустой экран. Другими словами, всегда размещайте это перед / за пределами document.ready . Я не проверял использование этого после загрузки страницы в событии щелчка или чем-то подобном, но я почти уверен, что это потерпит неудачу.

Мне понравилась идея расширения jQuery, но, очевидно, вам не нужно.

Перед вызовом document.writeln он проверяет, что скрипт еще не загружался, оценивая все элементы скрипта.

Я предполагаю, что сценарий не выполняется полностью до тех пор, пока не будет выполнено его событие document.ready. (Я знаю, что использование document.ready не обязательно, но многие используют его, и обработка этого является гарантией.)

Когда дополнительные файлы загружены, обратные вызовы document.ready будут выполняться в неправильном порядке. Чтобы решить эту проблему, когда скрипт действительно загружен, импортированный скрипт сам реимпортируется и выполнение останавливается. Это заставляет исходный файл теперь выполнять обратный вызов document.ready после любого из любых импортируемых им сценариев.

Вместо этого вы можете попытаться изменить jQuery readyList, но это выглядело как худшее решение.

Решение:

$.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;
    }
});

Использование:

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"
});
10
K.Dᴀᴠɪs 30 Мар 2018 в 21:22

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

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

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

//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('<script src="js/plugins/' + this + '.js"></script>');
});
  1. Вручную вызовите только один файл в вашей голове:
    <script src="js/plugins/plugins.js"></script>

НО:

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

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

9
rgb_life 10 Янв 2020 в 05:03

Заявление 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;
73
Peter Mortensen 11 Дек 2016 в 09:47

Хотя эти ответы великолепны, существует простое «решение», существующее с момента загрузки скрипта, и оно охватит 99,999% случаев использования большинства людей. Просто включите сценарий, который вам нужен, прежде чем сценарий, который требует этого. Для большинства проектов не требуется много времени, чтобы определить, какие сценарии нужны и в каком порядке.

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

Если script2 требует script1, это действительно самый простой способ сделать что-то подобное. Я очень удивлен, что никто не поднял этот вопрос, так как это самый очевидный и самый простой ответ, который применим почти в каждом отдельном случае.

12
KthProg 12 Апр 2018 в 19:38

Синтаксис @import для достижения CSS-подобного импорта JavaScript возможен с помощью такого инструмента, как Mixture, через их специальный тип файла .mix (см. здесь ). Я предполагаю, что приложение просто использует один из вышеупомянутых методов, хотя я не знаю.

Из документации Mixture в файлах .mix:

Файлы микширования - это просто файлы .js или .css с .mix. в имени файла. Файл микширования просто расширяет функциональность обычного файла стиля или скрипта и позволяет импортировать и комбинировать.

Вот пример файла .mix, который объединяет несколько файлов .js в один:

// 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 выводит это как scripts-global.js, а также как уменьшенную версию (scripts-global.min.js).

Примечание: я никоим образом не связан с Mixture, кроме того, что использую его как интерфейсный инструмент разработки. Я столкнулся с этим вопросом, увидев {JavaScript} в действии файл .mix JavaScript (в одном из шаблонов Mixture), и немного растерялся («Вы можете это сделать?» - подумал я про себя). Затем я понял, что это был тип файла приложения (несколько разочаровывающий, согласился). Тем не менее, полагал, что знание может быть полезным для других.

ОБНОВЛЕНИЕ : смесь теперь бесплатна (не в сети).

ОБНОВЛЕНИЕ : теперь микстура прекращена. Старые выпуски смесей по-прежнему доступны

14
ecv 17 Дек 2017 в 11:53

Можно динамически генерировать тег 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");
94
Peter Mortensen 28 Сен 2013 в 12:44

Может быть, вы можете использовать эту функцию, которую я нашел на этой странице Как включить JavaScript файл в файле JavaScript? :

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

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

    head.appendChild(script)
}
60
Ajeet Lakhani 15 Ноя 2014 в 17:01

Вы также можете собрать свои сценарии, используя PHP:

Файл 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
29
Peter Mortensen 28 Сен 2013 в 12:50

На современном языке с проверкой, если скрипт уже загружен, это будет:

function loadJs(url){
  return new Promise( (resolve, reject) => {
    if (document.querySelector(`head > script[src="${src}"]`) !== null) return resolve()
    const script = document.createElement("script")
    script.src = url
    script.onload = resolve
    script.onerror = reject
    document.head.appendChild(script)
  });
}

Использование (async / await):

try { await loadJs("https://.../script.js") } 
catch(error) {console.log(error)}

Или

await loadJs("https://.../script.js").catch(err => {})

Использование (обещание):

loadJs("https://.../script.js").then(res => {}).catch(err => {})
16
radulle 13 Янв 2020 в 07:50

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

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

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

< EM> SRC / main.js

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

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

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

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

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

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

< EM> сборки / main.js

var foo = function() {
    return {
          prop: "",
          method: function(){}
    }
};
28
Peter Mortensen 19 Окт 2014 в 18:13

Я только что написал этот код JavaScript (используя прототип для манипулирование DOM):

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

Использование:

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

Суть: http://gist.github.com/284442.

48
Talha Awan 25 Июн 2017 в 21:04

Мой обычный метод:

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

Это прекрасно работает и не использует перезагрузки страницы для меня. Я попробовал метод AJAX (один из других ответов), но, похоже, он мне не подходит.

Вот объяснение того, как работает код для любопытных: по сути, он создает новый тег сценария (после первого) URL-адреса. Он устанавливает его в асинхронный режим, чтобы не блокировать остальную часть кода, а вызывает обратный вызов, когда readyState (состояние загружаемого содержимого) меняется на «загружен».

13
Christopher Dumas 26 Авг 2017 в 17:02

Этот скрипт добавит файл 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);
})();
10
Peter Mortensen 19 Окт 2014 в 18:14

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

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

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

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

194
31piy 21 Мар 2018 в 04:29