Aqui está um exemplo mais concreto.
Estou trabalhando em um projeto com 60 arquivos. Temos dois modos diferentes de executá-lo.
Carregue uma versão concatenada, 1 arquivo grande. (Produção)
Carregue todos os 60 arquivos (desenvolvimento)
Estamos usando um carregador, então temos apenas um script na página da web
<script src="loader.js"></script>
O padrão é o modo 1 (carregando um arquivo concatenado grande). Para executar o modo 2 (arquivos separados), definimos alguma sinalização. Poderia ser qualquer coisa. Uma chave na string de consulta. Neste exemplo, apenas fazemos isso
<script>useDebugVersion = true;</script>
<script src="loader.js"></script>
loader.js tem algo parecido com isto
if (useDebugVersion) {
injectScript("app.js");
injectScript("somelib.js");
injectScript("someotherlib.js");
injectScript("anotherlib.js");
... repeat for 60 files ...
} else {
injectScript("large-concatinated.js");
}
O script de construção é apenas um arquivo .sh que se parece com isso
cat > large-concantinated.js app.js somelib.js someotherlib.js anotherlib.js
etc ...
Se um novo arquivo for adicionado, provavelmente usaremos o modo 2, pois estamos desenvolvendo, temos que adicionar uma injectScript("somenewfile.js")
linha ao loader.js
Mais tarde, para produção, também precisamos adicionar somenewfile.js ao nosso script de construção. Um passo que muitas vezes esquecemos e depois recebemos mensagens de erro.
Ao mudar para a AMD, não precisamos editar 2 arquivos. O problema de manter o loader.js e o script de compilação sincronizados desaparece. Usando r.js
ou webpack
ele pode simplesmente ler o código para criarlarge-concantinated.js
Ele também pode lidar com dependências, por exemplo, tivemos 2 arquivos lib1.js e lib2.js carregados assim.
injectScript("lib1.js");
injectScript("lib2.js");
lib2 precisa da lib1. Tem um código dentro que faz algo como
lib1Api.installPlugin(...);
Mas, como os scripts injetados são carregados de forma assíncrona, não há garantia de que eles serão carregados na ordem correta. Esses 2 scripts não são scripts da AMD, mas usando o require.js, podemos dizer suas dependências
require.config({
paths: {
lib1: './path/to/lib1',
lib2: './path/to/lib2',
},
shim: {
lib1: {
"exports": 'lib1Api',
},
lib2: {
"deps": ["lib1"],
},
}
});
I nosso módulo que usa lib1 fazemos isso
define(['lib1'], function(lib1Api) {
lib1Api.doSomething(...);
});
Agora, o require.js injetará os scripts para nós e não injetará a lib2 até que a lib1 seja carregada, pois informamos que a lib2 depende da lib1. Ele também não iniciará nosso módulo que usa lib1 até que ambos sejam carregados.
Isso torna o desenvolvimento agradável (sem etapa de compilação, sem se preocupar com a ordem de carregamento) e com a produção (sem a necessidade de atualizar um script de compilação para cada script adicionado).
Como um bônus adicional, podemos usar o plugin babel do webpack para executar o babel sobre o código em navegadores mais antigos e, novamente, não precisamos manter esse script de construção também.
Observe que, se o Chrome (nosso navegador preferido) começasse a oferecer suporte import
real, provavelmente mudaríamos para isso para desenvolvimento, mas isso realmente não mudaria nada. Ainda poderíamos usar o webpack para criar um arquivo concatenado e executar o babel sobre o código para todos os navegadores.
Tudo isso é obtido ao não usar tags de script e usar AMD