Як включити файл JavaScript в інший файл JavaScript?

Чи є в JavaScript щось схоже на @import в CSS, що дозволяє включати файл JavaScript в інший файл JavaScript?

4465
04 июня '09 в 14:59 2009-06-04 14:59 заданий Alec Smart 04 червня '09 о 14:59 2009-06-04 14:59
@ 56 відповідей
  • 1
  • 2

У старих версіях JavaScript не було імпорту, включення або вимоги, тому було розроблено багато різних підходів до цієї проблеми.

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

Для сумісності зі старими браузерами можна використовувати інструменти збірки та / або перенесення .

ES6 Модулі

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

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

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

Браузери підтримують завантаження модулів ECMAScript безпосередньо (не потрібні такі інструменти, як Webpack) починаючи з Safari 10.1, Chrome 61, Firefox 60 і Edge 16. Перевірте поточну підтримку в caniuse .

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

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

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

читайте на сторінці https://developers.google.com/web/updates/2017/11/dynamic-import. 

Node.js вимагає

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

 // 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 забезпечить регулярне в один рядок :

 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) } section of the page 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) } body section instead 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> в кінець розділу head сторінки, де атрибут src встановлений на URL-адресу, який передається функції в якості першого параметра.

Обидва ці рішення обговорюються і ілюструються в JavaScript Madness: динамічне завантаження скриптів .

Виявлення, коли скрипт був виконаний

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

Це означає, що якщо ви будете використовувати ці трюки безпосередньо, ви не зможете використовувати свій недавно завантажений код на наступному рядку після того, як ви попросили його завантажити, тому що він все ще буде завантажуватися.

Наприклад: my_lovely_script.js містить MySuperObject :

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

Потім ви пишете код, який хочете використовувати ПІСЛЯ того, як скрипт завантажується в лямбда-функцію :

 loadScript("my_lovely_script.js", myPrettyCode); 

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

Злиття / попередня обробка вихідного коду

Як згадувалося у верхній частині цієї відповіді, багато розробників використовують в своїх проектах інструменти збірки / перенесення, такі як Parcel, Webpack або Babel, що дозволяє їм використовувати майбутній синтаксис JavaScript, забезпечувати сумісність для старих браузерів, об'єднувати файли, мінімізувати, виконувати розбиття коду і т.д.

3838
04 июня '09 в 15:13 2009-06-04 15:13 відповідь дан e-satis 04 червня '09 о 15:13 2009-06-04 15:13

Якщо хтось шукає щось більш просунуте, спробуйте RequireJS . Ви отримаєте додаткові переваги, такі як управління залежностями, покращений паралелізм і уникнути дублювання (тобто отримання сценарію більш ніж один раз).

Ви можете записати свої файли JavaScript в "модулі", а потім посилатися на них як на залежності в інших скриптах. Або ви можете використовувати RequireJS як просте рішення "йди і отримай цей скрипт".

приклад:

Визначте залежності як модулі:

деякі-dependency.js

border=0
 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.

...

532
07 июня '12 в 23:55 2012-06-07 23:55 відповідь дан John Strickler 07 червня '12 о 23:55 2012-06-07 23:55

Насправді є спосіб завантажити файл JavaScript НЕ асинхронно, так що ви можете використовувати функції, включені в ваш недавно долучення, відразу після завантаження, і я думаю, що він працює у всіх браузерах.

Вам потрібно використовувати jQuery.append() в елементі <head> вашої сторінки, тобто:

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

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

Але якщо це не проблема для вас, тоді цей метод повинен працювати.

Насправді я написав плагін jQuery з ім'ям $ .import_js (), який використовує цей метод:

 (function($) {  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).

173
28 апр. відповідь дан Kipras 28 Квітня. 2011-04-28 18:25 '11 о 18:25 2011-04-28 18:25

Інший спосіб, який, на мій погляд, набагато чистіше, - це зробити синхронний 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(); 
138
08 сент. відповідь дан Ariel 08 сент. 2011-09-08 21:22 '11 о 21:22 2011-09-08 21:22

Для вас є хороші новини. Дуже скоро ви зможете легко завантажити код JavaScript. Це стане стандартним способом імпорту модулів коду JavaScript і стане частиною самого ядра JavaScript.

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

Таким чином, вам не потрібно покладатися на будь-яку інфраструктуру JavaScript і не потрібно явно робити виклики Ajax .

Посилатися на:

90
03 июля '12 в 16:32 2012-07-03 16:32 відповідь дан Imdad 03 липня '12 о 16:32 2012-07-03 16:32

Можна динамічно генерувати тег 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"); 
78
04 июня '09 в 15:02 2009-06-04 15:02 відповідь дан Svitlana Maksymchuk 04 червня '09 о 15:02 2009-06-04 15:02

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; 
61
17 апр. відповідь дан draupnie 17 Квітня. 2015-04-17 04:56 '15 о 4:56 2015-04-17 4:56

Може бути, ви можете скористатися цією функцією, яку я знайшов на цій сторінці Як мені включити файл 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) } 
51
04 июня '09 в 15:04 2009-06-04 15:04 відповідь дан Arnaud Gouder de Beauregard 04 червня '09 о 15:04 2009-06-04 15:04

Ось синхронна версія без 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 в своїй відповіді.

47
11 дек. відповідь дан heinob 11 дек. 2013-12-11 14:54 '13 о 14:54 2013-12-11 14:54

Я тільки що написав цей код JavaScript (використовуючи Prototype для маніпулювання 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); } }); })(); up to the 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 () {  }); </script> 

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

43
23 янв. відповідь дан nornagon 23 Січня. 2010-01-23 08:20 '10 о 8:20 2010-01-23 8:20

Ось узагальнена версія того, як Facebook робить це для їх всюдисущої кнопки "Подобається":

http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/ . 

36
08 июля '15 в 5:41 2015-07-08 05:41 відповідь дан Dan Dascalescu 08 липня '15 в 5:41 2015-07-08 5:41

Якщо ви хочете в чистому JavaScript, ви можете використовувати document.write .

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

Якщо ви використовуєте бібліотеку jQuery, ви можете використовувати метод $.getScript .

 $.getScript("another_script.js"); 
30
13 нояб. відповідь дан Venu immadi 13 листопада. 2013-11-13 12:18 '13 о 12:18 2013-11-13 12:18

Це, мабуть, найбільша слабкість JavaScript на мій погляд. Протягом багатьох років у мене не було проблем з відстеженням залежностей. У будь-якому випадку, здається, що єдине практичне рішення - це використовувати скрипт, включений в HTML файл, і, таким чином, жахливо зробити ваш код JavaScript залежним від користувача, включаючи потрібний вам джерело, і зробити його повторне використання недружнім.

Вибачте, якщо це звучить як лекція;) Це моя (погана) звичка, але я хочу підкреслити це.

Проблема повертається до того ж, що і все інше в мережі, до історії JavaScript. Це дійсно не було розроблено, щоб використовуватися в широкому поширенні, яке це використовувало сьогодні. Netscape створив мову, який дозволяв би вам керувати кількома речами, але вони не припускали його широкого використання для багатьох речей, як це прийнято зараз, і по тій або іншій причині він розширився звідти, не зачіпаючи деякі фундаментальні слабкі сторони оригінальної стратегії.

Це не один, звичайно. HTML не був розроблений для сучасної веб-сторінки; він був розроблений для того, щоб висловити логіку документа, щоб читачі (браузери в сучасному світі) могли відображати це у відповідній формі, яка була в межах можливостей системи, і потрібні були роки для вирішення (інше ніж зламати MS і Netscape). CSS вирішує цю проблему, але це було довгий час і навіть довше, щоб змусити людей використовувати його, а не усталені методи BAD. Це сталося, хвала.

Сподіваємося, що JavaScript (особливо тепер він є частиною стандарту) буде розвиватися, щоб прийняти концепцію правильної модульности (а також деяких інших речей), як і будь-який інший (існуючий) мову програмування в світі, і ця дурість зникне. До тих пір, поки тобі просто не сподобається і я не прийму це, я боюся.

30
24 мая '12 в 12:51 2012-05-24 12:51 відповідь дан Stephen Whipp 24 травня '12 о 12:51 2012-05-24 12:51

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

Отже, ось компілятор 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(){} } }; 
24
14 июля '13 в 0:44 2013-07-14 00:44 відповідь дан Dmitry Sheiko 14 липня '13 в 0:44 2013-07-14 00:44

Ви також можете зібрати свої скрипти, використовуючи 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 
24
28 дек. відповідь дан Calmarius 28 дек. 2010-12-28 00:03 '11 в 0:03 2010-12-28 00:03

Якщо ваше намір завантажити файл 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> 
20
24 июля '15 в 9:53 2015-07-24 09:53 відповідь дан Adem İlhan 24 липня '15 в 9:53 2015-07-24 9:53

Це повинно зробити:

 xhr = new XMLHttpRequest(); xhr.open("GET", "/soap/ajax/11.0/connection.js", false); xhr.send(); eval(xhr.responseText); 
18
24 марта '13 в 22:32 2013-03-24 22:32 відповідь дан tggagne 24 березня '13 о 22:32 2013-03-24 22:32

Або замість включення під час виконання використовуйте сценарій для об'єднання перед завантаженням.

Я використовую Зірочки (я не знаю, чи є інші). Ви будуєте свій код JavaScript в окремих файлах і включаєте коментарі, які обробляються механізмом Sprockets, як і включені. Для розробки ви можете включити файли послідовно, а потім для виробництва, щоб об'єднати їх ...

Дивіться також:

17
07 июня '12 в 23:48 2012-06-07 23:48 відповідь дан JMawer 07 червня '12 о 23:48 2012-06-07 23:48

Якщо ви використовуєте Web Workers і хочете включити в область працівника додаткові сценарії, інші відповіді про додавання сценаріїв в тег head і т.д. Не працюватимуть для вас.

На щастя, у Web Workers є своя власна функція importScripts яка є глобальною функцією в області Web Worker, вбудованої в сам браузер, оскільки є частиною специфікації .

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

14
01 янв. відповідь дан Turnerj 01 Січня. 2015-01-01 11:58 '15 о 11:58 2015-01-01 11:58

У мене була проста проблема, але я був здивований відповідями на це питання.

Мені довелося використовувати змінну (myVar1), визначену в одному файлі JavaScript (myvariables.js) в іншому файлі JavaScript (main.js).

Для цього я зробив, як показано нижче: