Есть ли что-то в JavaScript, похожее на @ import
в CSS, которое позволяет включать файл JavaScript в другой файл JavaScript?
Старые версии JavaScript не имели импорта, включения или требования, поэтому было разработано много различных подходов к этой проблеме.
Но с 2015 года (ES6) JavaScript имеет стандарт ES6 modules для импорта модулей в Node.js, который также поддерживается [большинством современных браузеров] ( https ://caniuse.com/#feat=es6-модуль).
Для совместимости со старыми браузерами можно использовать инструменты build и / или transpilation.
Модули ECMAScript (ES6) поддерживаются в Node.js с версии 8.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 (никакие инструменты, такие как Webpack, не требуются) с тех пор 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);
}
Узнайте больше на https://jakearchibald.com/2017/es-modules-in-browers/
Динамический импорт позволяет сценарию загружать другие сценарии по мере необходимости:
<script type="module">
import('hello.mjs').then(module => {
module.hello('world');
});
</script>
Узнайте больше на https://developers.google.com/web/updates/2017/11/dynamic-import
Старый стиль импорта модулей, все еще широко используемый в 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, а затем использовать eval
для его запуска. Это самый простой способ, но он ограничен вашим доменом из-за модели безопасности песочницы JavaScript. Использование eval
также открывает двери для ошибок, взломов и проблем безопасности.
Как и Dynamic Imports, вы можете загрузить один или несколько сценариев с помощью вызова 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 обеспечивает функцию загрузки в одной строке:
$.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: загрузка динамического скрипта.
Теперь есть большая проблема, о которой вы должны знать. Это означает, что вы удаленно загружаете код . Современные веб-браузеры будут загружать файл и продолжать выполнять ваш текущий скрипт, потому что они загружают все асинхронно для повышения производительности. (Это относится как к методу 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 < / kbd >. И это работает! Смущает...
Так что с этим делать ?
Ну, вы можете использовать взлом, который автор предлагает в ссылке, которую я вам дал. Таким образом, для людей, которые спешат, он использует событие для запуска функции обратного вызова при загрузке сценария. Таким образом, вы можете поместить весь код с помощью удаленной библиотеки в функцию обратного вызова. Например:
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);
}
Затем вы пишете код, который хотите использовать ПОСЛЕ загрузки скрипта в функцию lambda:
var myPrettyCode = function() {
// Here, do whatever you want
};
Тогда вы запускаете все это:
loadScript("my_lovely_script.js", myPrettyCode);
Обратите внимание, что скрипт может выполняться после загрузки DOM или до этого, в зависимости от браузера и от того, включили ли вы строку script.async = false;
. Есть отличная статья о загрузке Javascript в целом, в которой обсуждается это.
Как упомянуто в верхней части этого ответа, многие разработчики используют в своих проектах инструменты сборки / переплета, такие как Parcel, Webpack или Babel, что позволяет им использовать предстоящий синтаксис JavaScript, обеспечивает обратную совместимость для старых браузеров, объединяет файлы, измельчает, выполнить разделение кода и т. д.
Если кто-то ищет что-то более продвинутое, попробуйте RequireJS. Вы получите дополнительные преимущества, такие как управление зависимостями, лучший параллелизм и избегание дублирования (то есть извлечение сценария более одного раза).
Вы можете написать свои файлы JavaScript в «модулях», а затем ссылаться на них как на зависимости в других скриптах. Или вы можете использовать RequireJS как простое решение «перейти к этому сценарию».
Пример:
Определите зависимости как модули:
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 - это ваш «основной» файл 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, а также более определенные модули. Он оптимизирован для использования в браузере, в том числе в Интернете Рабочий, но его можно использовать в других средах JavaScript, например Носорог и узел. Он реализует API асинхронных модулей
RequireJS использует простые теги сценариев для загрузки модулей / файлов, так что это должно быть позволяют легко отлаживать. Его можно использовать просто для загрузки существующих Файлы JavaScript, так что вы можете добавить его в свой существующий проект без необходимость переписать ваши файлы JavaScript.
...
На самом деле is способ загрузить файл JavaScript not асинхронно, чтобы вы могли использовать функции, включенные в ваш недавно загруженный файл, сразу после его загрузки, и я думаю, что он работает во всех браузерах.
Вам необходимо использовать jQuery.append ()
в элементе < head >
, который:
$("head").append('<script type="text/javascript" src="' + script + '"></script>');
Однако, у этого метода также есть проблема: если в импортированном файле JavaScript произошла ошибка, ,[Firebug]1] ,(а также Firefox Error Console и [Инструменты разработчика Chrome]2] также) сообщит о своем месте неправильно, это большая проблема, если вы используете 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).
Другой способ, который, на мой взгляд, намного чище, - это сделать синхронный запрос 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();
Есть хорошие новости для вас. Очень скоро вы сможете легко загрузить код JavaScript. Это станет стандартным способом импорта модулей кода JavaScript и станет частью самого основного JavaScript.
Вам просто нужно написать import cond из 'cond.js';
, чтобы загрузить макрос с именемcond
из файлаcond.js
.
Таким образом, вам не нужно полагаться на какие-либо рамки JavaScript, а также не нужно явно совершать вызовы Ajax.
Обратитесь к:
[3]: http://wiki.ecmascript.org/doku.php?id = гармония: module_loaders
Можно динамически генерировать тег 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");
Заявление 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;
Может быть, вы можете использовать эту функцию, которую я нашел на этой странице [Как включить файл JavaScript в файл JavaScript?][1] :
function include(filename)
{
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';
head.appendChild(script)
}
[1]: http://forums.digitalpoint.com/showthread.php?t = 146094
Вот синхронная версия без 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» в своем ответе.
Я только что написал этот код 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.
Вот обобщенная версия того, как Facebook делает это для своей вездесущей кнопки «Мне нравится»
& Лт;!- начать фрагмент: js скрыть: false - >
<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/.
Если вы хотите в чистом JavaScript, вы можете использовать document.write
.
document.write('<script src="myscript.js" type="text/javascript"></script>');
Если вы используете библиотеку jQuery, вы можете использовать метод $ .getScript
.
$.getScript("another_script.js");
Вы также можете собрать свои сценарии, используя 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
Большинство решений, показанных здесь, подразумевают динамическую нагрузку. Вместо этого я искал компилятор, который собирал все зависающие файлы в один выходной файл. Так же, как препроцессоры Less / Sass имеют дело с правилом CSS @import
. Поскольку я не нашел ничего приличного в этом роде, я написал простой инструмент для решения проблемы.
Итак, вот компилятор https://github.com/dsheiko/jsic, который надежно заменяет $ import ("file-path")
запрашиваемым содержимым файла. Вот соответствующий плагин Grunt: https://github.com/dsheiko/grunt-jsic.
В основной ветке jQuery они просто объединяют файлы атомного источника в один, начиная с intro.js
и заканчивая outtro.js
. Это меня не устраивает, так как не обеспечивает гибкости при разработке исходного кода. Проверьте, как это работает с jsic:
var foo = $import("./Form/Input/Tel");
function() {
return {
prop: "",
method: function(){}
}
}
Теперь мы можем запустить компилятор:
node jsic.js src/main.js build/mail.js
И получите объединенный файл
build / main.js
var foo = function() {
return {
prop: "",
method: function(){}
}
};
Если вы хотите загрузить файл JavaScript с использованием функций из импортированного / включенного файла , вы также можете определить глобальный объект и установить функции в качестве элементов объекта. Например:
A = {};
A.func1 = function() {
console.log("func1");
}
A.func2 = function() {
console.log("func2");
}
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>
Или вместо включения во время выполнения используйте скрипт для объединения перед загрузкой.
Я использую Прокетки (я не знаю, есть ли другие). Вы создаете свой код JavaScript в отдельных файлах и включаете комментарии, которые обрабатываются механизмом Sprockets в том виде, в каком они есть. Для разработки вы можете включать файлы последовательно, а затем для производства, чтобы объединить их...
Смотрите также:
Если вы используете Web Workers и хотите включить дополнительные сценарии в область действия работника, другие ответы предоставляются о добавлении сценариев в тег head
и т. Д. не будет работать для вас.
К счастью, Web Workers имеют свою собственную функцию importScripts
, которая является глобальной функцией в области веб-работника, которая является родной для самого браузера, поскольку она является частью спецификации.
Кроме того, как второй самый высокий ответ, проголосовавший за ваш вопрос, RequireJS также может обрабатывать включение скриптов в веб-работника (вероятно, называя «importScripts» сам, но с некоторыми другими полезными функциями).
У меня была простая проблема, но я был озадачен ответами на этот вопрос.
Мне пришлось использовать переменную (myVar1), определенную в одном файле JavaScript (myvariables.js) в другом файле JavaScript (main.js).
Для этого я сделал, как ниже:
Загрузил код JavaScript в файле HTML, в правильном порядке, сначала mystariables.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 автоматически.
Это спасло мой день. Я надеюсь, что это поможет.
Синтаксис @ import
для достижения импорта JavaScript в стиле CSS возможен с помощью инструмента, такого как [Mixture] (), через их специальный тип файла .mix
(см. Здесь). Я предполагаю, что приложение просто использует один из вышеупомянутых методов в отдельности, хотя я не знаю.
Из документации по смеси в файлах .mix
:
Файлы Mix - это просто файлы .js или .css с .mix. в имени файла. A файл 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";
Смесь выводит это как scripts-global.js
, а также как минифицированная версия (scripts-global.min.js
).
Примечание: я никоим образом не связан с Mixture, кроме как использовать его в качестве внешнего инструмента разработки. Я столкнулся с этим вопросом, увидев файл JavaScript .mix
в действии (в одной из котельных смесей) и немного смутившись этим («вы можете сделать это?"Я думал про себя). Тогда я понял, что это был тип файла для конкретного приложения (несколько разочаровывающий, согласованный). Тем не менее, понял, что знания могут быть полезны для других.
ОБНОВЛЕНИЕ : Смесь теперь бесплатная (офлайн).
ОБНОВЛЕНИЕ : Смесь сейчас снята с производства. Старые выбросы смеси все еще доступны