summaryrefslogtreecommitdiffhomepage
path: root/pt-br/amd.html.markdown
blob: 38c1f70fb42318aefac7715c12f7db01629c30dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
---
category: tool
tool: amd
contributors:
    - ["Frederik Ring", "https://github.com/m90"]
translators:
    - ["Felipe Tarijon", "http://nanoincub.com/"]
lang: pt-br
filename: learnamd-pt.js
---

## Começando com AMD

A API de Definição de Módulos Assíncrona **Asynchronous Module Definition** 
especifica um mecanismo para definição de módulos em JavaScript para os quais o
módulo e suas dependências podem ser carregados de forma assíncrona. Isso é
particularmente bem adequado para o ambiente do browser onde o carregamento de
módulos de forma síncrona fica sujeito a problemas de performance, usabilidade,
debugging e problemas de acesso em requisições cross-domain.

### Conceito básico
```javascript
// O básico da API de AMD consiste de nada mais que dois métodos: `define` e `require`
// e isso é tudo sobre a definição de módulo e consumo:
// `define(id?, dependências?, factory)` define um módulo
// `require(dependências, callback)` importa uma série de dependências e
// consome elas no callback passado como parâmetro.

// Vamos começar usando o define para definir um novo módulo
// que não tem dependências. Nós vamos fazer isso passando um nome
// e uma função factory para definir:
define('awesomeAMD', function(){
  var isAMDAwesome = function(){
    return true;
  };
  // O valor retornado da função de factory do módulo é
  // o que os outros módulos ou chamadas de require irão
  // receber quando requisitarem nosso módulo `awesomeAMD`.
  // O valor exportado pode ser qualquer coisa, (construtor) funções,
  // objetos, primitives, até mesmo undefined (apesar de que não irão ajudar muito).
  return isAMDAwesome;
});

// Agora, vamos definir outro módulo que depende do nosso módulo `awesomeAMD`.
// Perceba que existe um argumento adicional definindo nossas dependências do
// módulo agora:
define('loudmouth', ['awesomeAMD'], function(awesomeAMD){
  // dependências serão passadas como argumentos da factory
  // na ordem que elas forem especificadas
  var tellEveryone = function(){
    if (awesomeAMD()){
      alert('Isso é tãaaao loko!');
    } else {
      alert('Bem estúpido, né não?');
    }
  };
  return tellEveryone;
});

// Agora que nós sabemos como usar o define, vamos usar o `require` para
// começar nosso programa. A assinatura do `require` é `(arrayDedependências, callback)`.
require(['loudmouth'], function(loudmouth){
  loudmouth();
});

// Para fazer esse tutorial executável, vamos implementar uma versão muito básica
// (não-assíncrona) de AMD bem aqui nesse lugar:
function define(nome, deps, factory){
  // perceba como os módulos sem dependências são manipulados
  define[nome] = require(factory ? deps : [], factory || deps);
}

function require(deps, callback){
  var args = [];
  // primeiro vamos recuperar todas as dependências necessárias
  // pela chamada requerida
  for (var i = 0; i < deps.length; i++){
    args[i] = define[deps[i]];
  }
  // corresponder todas as dependências da função de callback
  return callback.apply(null, args);
}
// você pode ver esse código em ação aqui: http://jsfiddle.net/qap949pd/
```

### Uso na vida real com require.js

Em contraste com o exemplo introdutório, `require.js` (a biblioteca mais popular de AMD) na verdade implementa o **A** do **AMD**, permitindo que você carregue os módulos e suas
dependências via XHR:

```javascript
/* file: app/main.js */
require(['modules/algumaClasse'], function(AlgumaClasse){
  // o callback é deferido até que a dependencia seja carregada
  var coisa = new AlgumaClasse();
});
console.log('Então aqui estamos nós, esperando!'); // isso vai rodar primeiro
```

Por convenção, você geralmente guarda um módulo em um arquivo. `require.js` pode resolver nome de módulos baseado no caminho das pastas, então você não precisa nomear os seus módulos, mas sim simplesmente referenciar eles usando sua origem. No exemplo `algumaClasse` é adotado a pasta `modules`, relativa a configuração da sua `baseUrl`:

* app/
  * main.js
  * modules/
    * algumaClasse.js
    * algunsHelpers.js
    * ...
  * daos/
    * coisas.js
    * ...

Isso significa que nós podemos definir `algumaClasse` sem especificar o id de um módulo:

```javascript
/* arquivo: app/modules/algumaClasse.js */
define(['daos/coisas', 'modules/algunsHelpers'], function(coisasDao, helpers){
  // definição de módulo, claro, irá acontecer também de forma assíncrona
  function AlgumaClasse(){
    this.metodo = function(){/**/};
    // ...
  }
  return AlgumaClasse;
});
```
Para alterar o comportamento padrão de mapeamento de caminho de pastas utilize
`requirejs.config(configObj)` em seu `main.js`:

```javascript
/* arquivo: main.js */
requirejs.config({
  baseUrl : 'app',
  paths : {
    // você pode também carregar módulos de outros locais
    jquery : '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min',
    coolLibFromBower : '../bower_components/cool-lib/coollib'
  }
});
require(['jquery', 'coolLibFromBower', 'modules/algunsHelpers'], function($, coolLib, helpers){
  // um arquivo `main` precisa chamar o require pelo menos uma vez,
  // caso contrário, o código jamais rodará
  coolLib.facaAlgoDoidoCom(helpers.transform($('#foo')));
});
```
Apps baseados em `require.js` geralmente terão u´m único ponto de acesso (`main.js`) que é passado à tag script do `require.js` como um data-attribute. Ele vai ser automaticamente carregado e executado com o carregamento da página:

```html
<!DOCTYPE html>
<html>
<head>
  <title>Umas 100 tags de script? Nunca mais!</title>
</head>
<body>
  <script src="require.js" data-main="app/main"></script>
</body>
</html>
```

### Otimizando um projeto inteiro utilizando r.js

Muitas pessoas preferem usar AMD para sanar a organização do código durante o desenvolvimento, mas continuam querendo colocar um único arquivo de script em produção ao invés de realizarem centenas de requisições XHRs no carregamento da página.

`require.js` vem com um script chamado `r.js` (que você vai provavelmente rodar em node.js, embora Rhino suporte também) que você pode analisar o gráfico de dependências de seu projeto, e fazer em um único arquivo contendo todos os seus módulos (corretamente nomeados), minificados e prontos para serem consumidos.

Instale-o utilizando `npm`:
```shell
$ npm install requirejs -g
```

Agora você pode alimentá-lo com um arquivo de configuração:
```shell
$ r.js -o app.build.js
```

Para o nosso exemplo acima a configuração pode ser essa:
```javascript
/* file : app.build.js */
({
  name : 'main', // nome do ponto de acesso
  out : 'main-built.js', // nome o arquivo para gravar a saída
  baseUrl : 'app',
  paths : {
    // `empty:` fala para o r.js que isso ainda deve ser baixado da CDN, usando
    // o local especificado no `main.js`
    jquery : 'empty:',
    coolLibFromBower : '../bower_components/cool-lib/coollib'
  }
})
```

Para usar o arquivo gerado, em produção, simplesmente troque o `data-main`:
```html
<script src="require.js" data-main="app/main-built"></script>
```

Uma incrível e detalhada visão geral [de build options](https://github.com/jrburke/r.js/blob/master/build/example.build.js) está disponível no repositório do GitHub.

### Tópicos não abordados nesse tutorial
* [Plugins de carregamento / transforms](http://requirejs.org/docs/plugins.html)
* [CommonJS style carregamento e exportação](http://requirejs.org/docs/commonjs.html)
* [Configuração avançada](http://requirejs.org/docs/api.html#config)
* [Shim configuration (carregando módulos sem AMD)](http://requirejs.org/docs/api.html#config-shim)
* [Carregando e otimizando CSS com require.js](http://requirejs.org/docs/optimization.html#onecss)
* [Usando almond.js para builds](https://github.com/jrburke/almond)

### Outras leituras:

* [Especificação oficial](https://github.com/amdjs/amdjs-api/wiki/AMD)
* [Por quê AMD?](http://requirejs.org/docs/whyamd.html)
* [Universal Module Definition](https://github.com/umdjs/umd)

### Implementações:

* [require.js](http://requirejs.org)
* [dojo toolkit](http://dojotoolkit.org/documentation/tutorials/1.9/modules/)
* [cujo.js](http://cujojs.com/)
* [curl.js](https://github.com/cujojs/curl)
* [lsjs](https://github.com/zazl/lsjs)
* [mmd](https://github.com/alexlawrence/mmd)