segunda-feira, 28 de janeiro de 2013

Carregando vários scripts adicionando uma tag só

Olá a todos,

Este é rapidinho, alguns de vocês não terão uso prático para isto porque... é muito específico. Na verdade é quase uma curiosidade, uma vez que as técnicas de "minifização" e junção de arquivos estão muito evoluídas. Ainda assim, eis o cenário:

Imagine que você tem um biblioteca javascript dividida em vários artefatos, mas você não quer obrigar os usuários da sua biblioteca a adicionar todos os arquivos. Você quer que eles adicionem um só e saiam usando.

A solução envolve adicionar um único script, mas este adicionará os outros dinamicamente. Mais ou menos assim:

/* arquivo bootstrap.js */
(function(d){
 var scripts = d.scripts;
 var path = "";
 for ( var i in scripts) {
  var cap = null;
  if (scripts[i].src)
   cap = scripts[i].src.replace(/.*(bootstrap.js)/, "$1");
  if ("bootstrap.js" == cap) {
   path = scripts[i].src.replace(/(.*)bootstrap.js/, "$1");
   break;
  }
 }
 // lista com todos os modulos
 var modules = [ "module1.js", "module2.js", "module3.js", "module4.js" ];
 for ( var i in modules) {
  var script = d.createElement("script");
  script.src = path + modules[i];
  d.head.appendChild(script);
 }
})(document);

Neste caso compreende-se que o bootstrap e os módulos estão em um mesmo diretório, por isso a lista de módulos possui somente o nome dos arquivos. Caso houvesse pastas, a lista teria nomes como "pastaX/moduloA.js" e tudo estaria certo.

Uma desvantagem séria é que se você precisar dos artefatos da biblioteca ainda na fase de carregamento da página eles ainda não estarão la. As tags de script ainda serão carregadas.

A versão abaixo procura corrigir este problema, mas vai obrigar-lhe a ter um "entrypoint" obscuro (facebook, é com você, ouviu?) e lá declarar tudo o que for preciso na fase de carregamento:

/* arquivo bootstrap.js */
(function(d){
 var scripts = d.scripts;
 var path = "";
 for ( var i in scripts) {
  var cap = null;
  if (scripts[i].src)
   cap = scripts[i].src.replace(/.*(bootstrap.js)/, "$1");
  if ("bootstrap.js" == cap) {
   path = scripts[i].src.replace(/(.*)bootstrap.js/, "$1");
   break;
  }
 }
 // lista com todos os modulos
 var modules = [ "module1.js", "module2.js", "module3.js", "module4.js" ];
 var loaded=0;
 function anotherLoad() {
  if(loaded == modules.length){
   // defina window.bootStrapMain=function(){} na sua fase de
   // carregamento, onde antes havia onloads e outras coisas.
   window.bootStrapMain();
  }
 }
 for ( var i in modules) {
  var script = d.createElement("script");
  script.onload = function() {
   loaded++;
   anotherLoad();
  };
  script.src = path + modules[i];
  d.head.appendChild(script);
 }
})(document);

Dessa forma você terá uma maneira simples de disparar o carregamento da aplicação encadeado ao carregamento da biblioteca.

Sem mais e até a próxima.

Nenhum comentário :

Postar um comentário