Existe algo em JavaScript semelhante ao @import
CSS que permite incluir um arquivo JavaScript dentro de outro arquivo JavaScript?
script
tags ordenadas ?
Existe algo em JavaScript semelhante ao @import
CSS que permite incluir um arquivo JavaScript dentro de outro arquivo JavaScript?
script
tags ordenadas ?
Respostas:
As versões antigas do JavaScript não tinham importação, inclusão ou exigência, muitas abordagens diferentes para esse problema foram desenvolvidas.
Mas desde 2015 (ES6), o JavaScript possui o padrão dos módulos ES6 para importar módulos no Node.js., que também é suportado pelos navegadores mais modernos .
Para compatibilidade com navegadores antigos, crie ferramentas como Webpack e Rollup e / ou ferramentas de transpilação como Babel .
Os módulos ECMAScript (ES6) são suportados no Node.js. desde a v8.5, com o --experimental-modules
sinalizador, e desde pelo menos Node.js. v13.8.0, sem o sinalizador. Para ativar "ESM" (vs. sistema de módulos commonjs de estilo anterior Node.js [ "CJS"]) que você quer para uso "type": "module"
em package.json
ou dar os arquivos a extensão .mjs
. (Da mesma forma, os módulos gravados com o módulo CJS anterior do Node.js. podem ser nomeados .cjs
se o padrão for ESM.)
Usando package.json
:
{
"type": "module"
}
Então module.js
:
export function hello() {
return "Hello";
}
Então main.js
:
import { hello } from './module.js';
let val = hello(); // val is "Hello";
Usando .mjs
, você teria module.mjs
:
export function hello() {
return "Hello";
}
Então main.mjs
:
import { hello } from './module.mjs';
let val = hello(); // val is "Hello";
Os navegadores têm suporte para carregar módulos ECMAScript diretamente (não são necessárias ferramentas como o Webpack) desde o Safari 10.1, Chrome 61, Firefox 60 e Edge 16. Verifique o suporte atual no caniuse . Não há necessidade de usar a .mjs
extensão do Node.js. Os navegadores ignoram completamente as extensões de arquivo nos módulos / scripts.
<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);
}
Leia mais em https://jakearchibald.com/2017/es-modules-in-browsers/
As importações dinâmicas permitem que o script carregue outros scripts conforme necessário:
<script type="module">
import('hello.mjs').then(module => {
module.hello('world');
});
</script>
Leia mais em https://developers.google.com/web/updates/2017/11/dynamic-import
O estilo mais antigo do módulo CJS, ainda amplamente usado no Node.js, é o module.exports
/require
system.
// mymodule.js
module.exports = {
hello: function() {
return "Hello";
}
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"
Existem outras maneiras de o JavaScript incluir conteúdo externo de JavaScript em navegadores que não requerem pré-processamento.
Você pode carregar um script adicional com uma chamada AJAX e depois usá eval
-lo para executá-lo. Essa é a maneira mais direta, mas está limitada ao seu domínio devido ao modelo de segurança da sandbox JavaScript. O uso eval
também abre as portas para bugs, hacks e problemas de segurança.
Como as importações dinâmicas, você pode carregar um ou vários scripts com uma fetch
chamada usando promessas para controlar a ordem de execução das dependências de script usando a biblioteca 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)}`)
})
A biblioteca jQuery fornece a funcionalidade de carregamento em uma linha :
$.getScript("my_lovely_script.js", function() {
alert("Script loaded but not necessarily executed.");
});
Você pode adicionar uma tag de script com a URL do script no HTML. Para evitar a sobrecarga do jQuery, esta é uma solução ideal.
O script pode até residir em um servidor diferente. Além disso, o navegador avalia o código. A <script>
tag pode ser injetada na página da Web <head>
ou inserida imediatamente antes da </body>
tag de fechamento .
Aqui está um exemplo de como isso poderia funcionar:
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)
}
Esta função adicionará uma nova <script>
tag ao final da seção principal da página, onde o src
atributo é definido como o URL que é atribuído à função como o primeiro parâmetro.
Ambas as soluções são discutidas e ilustradas em JavaScript Madness: Dynamic Script Loading .
Agora, há um grande problema que você deve conhecer. Isso implica que você carrega remotamente o código . Navegadores modernos carregam o arquivo e continuam executando o script atual, porque carregam tudo de forma assíncrona para melhorar o desempenho. (Isso se aplica ao método jQuery e ao método de carregamento de script dinâmico manual.)
Isso significa que, se você usar esses truques diretamente, não poderá usar o código recém-carregado na próxima linha depois de solicitar que ele seja carregado , porque ainda estará carregando.
Por exemplo: my_lovely_script.js
contém 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
Então você recarrega a página acessando F5. E funciona! Confuso ...
Então o que fazer sobre isso ?
Bem, você pode usar o hack que o autor sugere no link que eu lhe dei. Em resumo, para pessoas com pressa, ele usa um evento para executar uma função de retorno de chamada quando o script é carregado. Assim, você pode colocar todo o código usando a biblioteca remota na função de retorno de chamada. Por exemplo:
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);
}
Em seguida, você escreve o código que deseja usar APÓS o script ser carregado em uma função lambda :
var myPrettyCode = function() {
// Here, do whatever you want
};
Então você executa tudo isso:
loadScript("my_lovely_script.js", myPrettyCode);
Observe que o script pode ser executado após o carregamento do DOM, ou antes, dependendo do navegador e se você incluiu a linha script.async = false;
. Há um ótimo artigo sobre carregamento de Javascript em geral que discute isso.
Como mencionado na parte superior desta resposta, muitos desenvolvedores usam ferramentas de compilação / transpilação como Parcel, Webpack ou Babel em seus projetos, permitindo que eles usem a próxima sintaxe JavaScript, forneçam compatibilidade com versões anteriores para navegadores antigos, combinem arquivos, minifiquem, executar divisão de código etc.
onreadystatechange
evento e a readyState
propriedade). Além disso, o carregamento dinâmico de scripts não se beneficia dos scanners de pré-carregamento do Bros. Recomende este artigo do HTML5Rocks: html5rocks.com/en/tutorials/speed/script-loading
Se alguém estiver procurando por algo mais avançado, experimente o RequireJS . Você receberá benefícios adicionais, como gerenciamento de dependência, melhor concorrência e evitará duplicação (ou seja, recuperando um script mais de uma vez).
Você pode gravar seus arquivos JavaScript em "módulos" e referenciá-los como dependências em outros scripts. Ou você pode usar o RequireJS como uma solução simples "vá buscar esse script".
Exemplo:
Defina dependências como módulos:
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
});
deployment.js é o seu arquivo JavaScript "principal" que depende de some-dependency.js
require(['some-dependency'], function(dependency) {
//Your script goes here
//some-dependency.js is fetched.
//Then your script is executed
});
Trecho do arquivo README do GitHub :
O RequireJS carrega arquivos JavaScript simples, bem como módulos mais definidos. É otimizado para uso no navegador, inclusive em um Trabalhador da Web, mas pode ser usado em outros ambientes JavaScript, como Rhino e Node. Ele implementa a API do módulo assíncrono.
O RequireJS usa tags de script simples para carregar módulos / arquivos, portanto, deve permitir a depuração fácil. Ele pode ser usado simplesmente para carregar arquivos JavaScript existentes, portanto você possa adicioná-lo ao seu projeto existente sem precisar reescrever seus arquivos JavaScript.
...
Na verdade, existe uma maneira de carregar um arquivo JavaScript de forma não assíncrona, para que você possa usar as funções incluídas no seu arquivo recém-carregado logo após carregá-lo, e acho que funciona em todos os navegadores.
Você precisa usar jQuery.append()
no <head>
elemento da sua página, ou seja:
$("head").append('<script type="text/javascript" src="' + script + '"></script>');
No entanto, esse método também tem um problema: se ocorrer um erro no arquivo JavaScript importado, o Firebug (e também o Firefox Error Console e o Chrome Developer Tools ) informarão seu lugar incorretamente, o que é um grande problema se você usar o Firebug para rastrear Erros de JavaScript caem muito (sim). O Firebug simplesmente não sabe sobre o arquivo recém-carregado por algum motivo; portanto, se ocorrer um erro nesse arquivo, ele informa que ocorreu no seu HTML principal arquivo e você terá problemas para descobrir a verdadeira razão do erro.
Mas se isso não for um problema para você, esse método deve funcionar.
Na verdade, eu escrevi um plugin jQuery chamado $ .import_js () que usa este método:
(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);
Portanto, tudo que você precisa fazer para importar o JavaScript é:
$.import_js('/path_to_project/scripts/somefunctions.js');
Também fiz um teste simples para isso no Exemplo .
Ele inclui um main.js
arquivo no HTML principal e, em seguida, o script é main.js
usado $.import_js()
para importar um arquivo adicional chamado included.js
, que define esta função:
function hello()
{
alert("Hello world!");
}
E logo após a inclusão included.js
, a hello()
função é chamada e você recebe o alerta.
(Esta resposta é uma resposta ao comentário do e-satis).
jQuery.getScript
, dessa forma você não precisa se preocupar em escrever o plugin ...
script
elemento ao head
fará com que ele seja executado de forma assíncrona, a menos que async
esteja definido especificamente como false
.
"
, código vai quebrar
Outra maneira, que na minha opinião é muito mais limpa, é fazer uma solicitação síncrona do Ajax em vez de usar uma <script>
tag. Também é assim que o Node.js lida com inclui.
Aqui está um exemplo usando o 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);
}
});
}
Em seguida, você pode usá-lo em seu código, como normalmente usaria uma inclusão:
require("/scripts/subscript.js");
E poder chamar uma função do script necessário na próxima linha:
subscript.doSomethingCool();
async: false
supostamente está obsoleto. Não é! Como sua cotação indica, apenas o material relacionado ao jqXHR é.
Há uma boa notícia para você. Em breve, você poderá carregar o código JavaScript facilmente. Ele se tornará uma maneira padrão de importar módulos de código JavaScript e fará parte do próprio JavaScript principal.
Você simplesmente precisa escrever import cond from 'cond.js';
para carregar uma macro chamada cond
de um arquivo cond.js
.
Portanto, você não precisa confiar em nenhuma estrutura JavaScript nem precisa fazer explicitamente chamadas para o Ajax .
Referir-se:
É possível gerar dinamicamente uma tag JavaScript e anexá-la ao documento HTML de outro código JavaScript. Isso carregará o arquivo JavaScript direcionado.
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");
js.onload = callback;
Declaração import
está no ECMAScript 6.
Sintaxe
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;
Talvez você possa usar esta função que encontrei nesta página. Como incluo um arquivo JavaScript em um arquivo 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)
}
script.onload = callback;
var
, a variável será global?
Aqui está uma versão síncrona sem 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);
}
Observe que, para obter esse domínio entre domínios, o servidor precisará definir o allow-origin
cabeçalho em sua resposta.
http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)
<script>
tag inserida , não por XMLHttpRequest
.
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
Acabei de escrever este código JavaScript (usando Prototype para manipulação de 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);
}
});
})();
Uso:
<script src="prototype.js"></script>
<script src="require.js"></script>
<script>
require(['foo.js','bar.js'], function () {
/* Use foo.js and bar.js here */
});
</script>
Gist: http://gist.github.com/284442 .
Aqui está a versão generalizada de como o Facebook faz isso por seu onipresente botão Curtir:
<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>
Se funcionar para o Facebook, funcionará para você.
A razão pela qual procuramos o primeiro script
elemento em vez de head
ou body
é porque alguns navegadores não criam um se estiverem ausentes, mas garantimos que temos um script
elemento - este. Leia mais em http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/ .
Se você deseja JavaScript puro, pode usar document.write
.
document.write('<script src="myscript.js" type="text/javascript"></script>');
Se você usar a biblioteca jQuery, poderá usar o $.getScript
método
$.getScript("another_script.js");
Você também pode montar seus scripts usando PHP :
Arquivo 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
A maioria das soluções mostradas aqui implica carregamento dinâmico. Eu estava procurando um compilador que reunisse todos os arquivos dependentes em um único arquivo de saída. O mesmo que os pré-processadores Less / Sass lidam com a @import
regra geral do CSS . Como não achei nada decente desse tipo, escrevi uma ferramenta simples para resolver o problema.
Então, aqui está o compilador, https://github.com/dsheiko/jsic , que substitui $import("file-path")
com segurança o conteúdo do arquivo solicitado. Aqui está o plug-in Grunt correspondente : https://github.com/dsheiko/grunt-jsic .
No ramo mestre do jQuery, eles simplesmente concatenam os arquivos de origem atômica em um único começando intro.js
e terminando com outtro.js
. Isso não combina comigo, pois não oferece flexibilidade no design do código-fonte. Confira como ele funciona com o jsic:
src / main.js
var foo = $import("./Form/Input/Tel");
src / Form / Input / Tel.js
function() {
return {
prop: "",
method: function(){}
}
}
Agora podemos executar o compilador:
node jsic.js src/main.js build/mail.js
E obtenha o arquivo combinado
build / main.js
var foo = function() {
return {
prop: "",
method: function(){}
}
};
Se sua intenção de carregar o arquivo JavaScript estiver usando as funções do arquivo importado / incluído , você também poderá definir um objeto global e definir as funções como itens de objeto. Por exemplo:
A = {};
A.func1 = function() {
console.log("func1");
}
A.func2 = function() {
console.log("func2");
}
A.func1();
A.func2();
Você só precisa ter cuidado ao incluir scripts em um arquivo HTML. O pedido deve ser como abaixo:
<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>
Isso deve fazer:
xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
eval
que há de errado com isso. De Crockford , " eval
é ruim. A eval
função é o recurso mais mal utilizado do JavaScript. Evite-o. eval
Possui aliases. Não use o Function
construtor. Não passe as strings para setTimeout
ou setInterval
". Se você ainda não leu o "JavaScript: The Good Parts", faça o mesmo agora. Você não vai se arrepender.
http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)
Ou, em vez de incluir no tempo de execução, use um script para concatenar antes do upload.
Eu uso rodas dentadas (não sei se existem outros). Você constrói seu código JavaScript em arquivos separados e inclui comentários que são processados pelo mecanismo Sprockets como inclui. Para o desenvolvimento, você pode incluir arquivos seqüencialmente e, em seguida, para a produção mesclá-los ...
Veja também:
Eu tinha um problema simples, mas fiquei perplexo com as respostas a essa pergunta.
Eu tive que usar uma variável (myVar1) definida em um arquivo JavaScript (myvariables.js) em outro arquivo JavaScript (main.js).
Para isso, fiz o seguinte:
Carregou o código JavaScript no arquivo HTML, na ordem correta, primeiro myvariables.js, depois main.js:
<html>
<body onload="bodyReady();" >
<script src="myvariables.js" > </script>
<script src="main.js" > </script>
<!-- Some other code -->
</body>
</html>
Arquivo: myvariables.js
var myVar1 = "I am variable from myvariables.js";
Arquivo: main.js
// ...
function bodyReady() {
// ...
alert (myVar1); // This shows "I am variable from myvariables.js", which I needed
// ...
}
// ...
Como você viu, eu usava uma variável em um arquivo JavaScript em outro arquivo JavaScript, mas não precisava incluir uma em outro. Eu só precisava garantir que o primeiro arquivo JavaScript carregado antes do segundo arquivo JavaScript e as variáveis do primeiro arquivo JavaScript estivessem acessíveis no segundo arquivo JavaScript automaticamente.
Isso salvou meu dia. Eu espero que isso ajude.
import
. Você precisa de um arquivo HTML para obter coisas de um arquivo js para outro.
<script>
tag. Isso pode ajudar na organização. Essa resposta simplesmente não é o que a pergunta estava pedindo e não é ideal nesse contexto.
Caso você esteja usando Trabalhadores da Web e queira incluir scripts adicionais no escopo do trabalhador, as outras respostas fornecidas sobre a adição de scripts aohead
tag etc. não funcionarão para você.
Felizmente, os Web Workers têm sua própria importScripts
função, que é uma função global no escopo do Web Worker, nativa do próprio navegador, pois faz parte da especificação .
Como alternativa, como destaca a segunda resposta mais votada para sua pergunta , o RequireJS também pode lidar com a inclusão de scripts dentro de um Web Worker (provavelmente se chamando importScripts
, mas com alguns outros recursos úteis).
Na linguagem moderna, com a verificação se o script já foi carregado, seria:
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)
});
}
Uso (assíncrono / aguardar):
try { await loadJs("https://.../script.js") }
catch(error) {console.log(error)}
ou
await loadJs("https://.../script.js").catch(err => {})
Uso (Promessa):
loadJs("https://.../script.js").then(res => {}).catch(err => {})
var pi = 3.14
. chamar a função loadJS () vialoadJs("pi.js").then(function(){ console.log(pi); });
A @import
sintaxe para obter a importação de JavaScript do tipo CSS é possível usando uma ferramenta como o Mixture por meio de seu .mix
tipo de arquivo especial (veja aqui ). Eu imagino que o aplicativo simplesmente use um dos métodos mencionados acima de forma interativa, embora eu não saiba.
Na documentação do Mixture em .mix
arquivos:
Os arquivos de mistura são simplesmente arquivos .js ou .css com .mix. no nome do arquivo. Um arquivo mix simplesmente amplia a funcionalidade de um estilo normal ou arquivo de script e permite importar e combinar.
Aqui está um .mix
arquivo de exemplo que combina vários .js
arquivos em um:
// 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";
A mistura produz isso como scripts-global.js
e também como uma versão minificada (scripts-global.min.js
).
Nota: Eu não sou afiliado de maneira alguma ao Mixture, além de usá-lo como uma ferramenta de desenvolvimento front-end. Me deparei com esta questão ao ver um.mix
arquivo JavaScript em ação (em um dos clichês do Mixture) e ficar um pouco confuso com ele ("você pode fazer isso?", Pensei comigo mesmo). Então percebi que era um tipo de arquivo específico do aplicativo (um pouco decepcionante, concordou). No entanto, percebi que o conhecimento pode ser útil para outras pessoas.
ATUALIZAÇÃO : A mistura agora é gratuita (offline).
ATUALIZAÇÃO : A mistura está descontinuada. Versões antigas de mistura ainda estão disponíveis
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
body
ainda não existe ou não pode ser modificado. Além disso, ajuda a explicar as respostas.
Meu método usual é:
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);
}
Ele funciona muito bem e não usa recargas de página para mim. Eu tentei o método AJAX (uma das outras respostas), mas ele não parece funcionar tão bem para mim.
Aqui está uma explicação de como o código funciona para aqueles que são curiosos: essencialmente, ele cria uma nova tag de script (após a primeira) da URL. Ele define o modo assíncrono para não bloquear o restante do código, mas chama um retorno de chamada quando o readyState (o estado do conteúdo a ser carregado) muda para 'carregado'.
Embora essas respostas sejam ótimas, existe uma "solução" simples que existe desde o carregamento do script, e cobrirá 99,999% dos casos de uso da maioria das pessoas. Basta incluir o script necessário antes do script que o requer. Para a maioria dos projetos, não demora muito para determinar quais scripts são necessários e em que ordem.
<!DOCTYPE HTML>
<html>
<head>
<script src="script1.js"></script>
<script src="script2.js"></script>
</head>
<body></body>
</html>
Se script2 requer script1, essa é realmente a maneira mais fácil de fazer algo assim. Estou muito surpreso que ninguém tenha levantado isso, pois é a resposta mais óbvia e mais simples que será aplicada em quase todos os casos.
Escrevi um módulo simples que automatiza o trabalho de importar / incluir scripts de módulo em JavaScript. Para obter uma explicação detalhada do código, consulte a postagem no blog JavaScript require / import / include modules .
// ----- 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);
};
Este script adicionará um arquivo JavaScript ao topo de qualquer outra <script>
tag:
(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);
})();
Há também Head.js . É muito fácil lidar com:
head.load("js/jquery.min.js",
"js/jquery.someplugin.js",
"js/jquery.someplugin.css", function() {
alert("Everything is ok!");
});
Como você vê, é mais fácil que o Require.js e tão conveniente quanto o $.getScript
método do jQuery . Ele também possui alguns recursos avançados, como carregamento condicional, detecção de recursos e muito mais .
Existem muitas respostas possíveis para essa pergunta. Minha resposta é obviamente baseada em várias delas. Foi isso que acabei depois de ler todas as respostas.
O problema $.getScript
e realmente qualquer outra solução que exija retorno de chamada quando o carregamento estiver concluído é que, se você tiver vários arquivos que o utilizam e dependem um do outro, não terá mais como saber quando todos os scripts foram carregados (uma vez aninhados em vários arquivos).
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...
});
Você está certo quando diz que pode especificar o Ajax para executar de forma síncrona ou usar XMLHttpRequest , mas a tendência atual parece ser descontinuar solicitações síncronas, portanto, talvez você não obtenha suporte total ao navegador agora ou no futuro.
Você pode tentar usar $.when
para verificar uma matriz de objetos adiados, mas agora está fazendo isso em todos os arquivos e o arquivo2 será considerado carregado assim que $.when
não for executado quando o retorno de chamada for executado, portanto, o arquivo1 ainda continuará a execução antes do carregamento do arquivo3 . Isso realmente ainda tem o mesmo problema.
Decidi voltar ao invés de avançar. Obrigado document.writeln
. Eu sei que é um tabu, mas contanto que seja usado corretamente, isso funcionará bem. Você acaba com um código que pode ser depurado facilmente, exibido corretamente no DOM e pode garantir a ordem em que as dependências são carregadas corretamente.
Obviamente, você pode usar $ ("body"). Append (), mas não poderá mais depurar corretamente.
NOTA: Você deve usá-lo apenas enquanto a página estiver carregando, caso contrário, você verá uma tela em branco. Em outras palavras, sempre coloque-o antes / fora do documento.ready . Eu não testei usando isso depois que a página foi carregada em um evento de clique ou algo assim, mas tenho certeza que ela falhará.
Gostei da idéia de estender o jQuery, mas obviamente você não precisa.
Antes de chamar document.writeln
, ele verifica se o script ainda não foi carregado, avaliando todos os elementos do script.
Presumo que um script não seja totalmente executado até que seu document.ready
evento seja executado. (Eu sei que o uso document.ready
não é obrigatório, mas muitas pessoas o usam, e lidar com isso é uma salvaguarda.)
Quando os arquivos adicionais são carregados, os document.ready
retornos de chamada são executados na ordem errada. Para resolver isso quando um script é realmente carregado, o script que o importou é reimportado e a execução é interrompida. Isso faz com que o arquivo de origem agora tenha seu document.ready
retorno de chamada executado após qualquer um dos scripts importados.
Em vez dessa abordagem, você poderia tentar modificar o jQuery readyList
, mas essa parecia uma solução pior.
Solução:
$.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;
}
});
Uso:
Arquivo3:
var f3obj = "file3";
// Define other stuff
$(function(){
f3obj = "file3docready";
});
Arquivo2:
$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
f2obj = "file2docready";
});
Arquivo1:
$.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"
});
Existem várias maneiras de implementar módulos em Javascript. Aqui estão as 2 mais populares:
Os navegadores ainda não oferecem suporte a esse sistema de modulação. Para usar essa sintaxe, você deve usar um bundler como o webpack. O uso de um bundler é melhor de qualquer maneira, pois isso pode combinar todos os seus arquivos diferentes em um único arquivo (ou em dois). Isso servirá os arquivos do servidor para o cliente mais rapidamente, pois cada solicitação HTTP possui alguma sobrecarga associada. Assim, ao reduzir a solicitação HTTP geral, melhoramos o desempenho. Aqui está um exemplo dos módulos 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
Este sistema de modulação é usado no NodeJS. Você basicamente adiciona suas exportações a um objeto chamado module.exports
. Você pode acessar esse objeto através de um require('modulePath')
. Importante aqui é perceber que esses módulos estão sendo armazenados em cache; portanto, se você tiver require()
um determinado módulo duas vezes, ele retornará o módulo já criado.
// 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
Cheguei a essa pergunta porque estava procurando uma maneira simples de manter uma coleção de plugins JavaScript úteis. Depois de ver algumas das soluções aqui, eu vim com isso:
Configure um arquivo chamado "plugins.js" (ou extensions.js ou o que você quiser). Mantenha seus arquivos de plug-in junto com esse único arquivo mestre.
plugins.js terá uma matriz chamada na pluginNames[]
qual iremos iterar e each()
, em seguida, anexar uma <script>
tag na cabeça de cada plug-in
//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>');
});
<script src="js/plugins/plugins.js"></script>
MAS:
Embora todos os plugins sejam inseridos na tag head da maneira que deveriam, eles nem sempre são executados pelo navegador quando você clica na página ou atualiza.
Descobri que é mais confiável escrever apenas as tags de script em um PHP include. Você só precisa escrevê-lo uma vez e isso funciona tanto quanto chamar o plugin usando JavaScript.