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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
|
---
title: Módulos JavaScript
slug: Web/JavaScript/Guide/Modules
translation_of: Web/JavaScript/Guide/Modules
original_slug: Web/JavaScript/Guide/Módulos
---
<div>{{JSSidebar("JavaScript Guide")}}{{Previous("Web/JavaScript/Guide/Meta_programming")}}</div>
<p>Este guia fornece tudo o que você precisa para começar com a sintaxe de módulo do JavaScript.</p>
<h2 id="Um_background_em_módulos">Um background em módulos</h2>
<p>Os programas JavaScript começaram muito pequenos - a maior parte do seu uso nos primeiros dias era para executar tarefas isoladas de script, fornecendo um pouco de interatividade às suas páginas da Web sempre que necessário, de modo que scripts grandes geralmente não eram necessários. Com o avanço rápido da tecnologia agora temos aplicativos completos sendo executados em navegadores com muito JavaScript, além de JavaScript ser usado em outros contextos (<a href="/en-US/docs/Glossary/Node.js">Node.js</a>, por exemplo).</p>
<p>Portanto, fez sentido nos últimos anos começar a pensar em fornecer mecanismos para dividir programas JavaScript em módulos separados que podem ser importados quando necessário. O Node.js possui essa capacidade há muito tempo e existem várias bibliotecas e estruturas JavaScript que permitem o uso do módulo (por exemplo, outros <a href="https://en.wikipedia.org/wiki/CommonJS">CommonJS</a> e <a href="https://github.com/amdjs/amdjs-api/blob/master/AMD.md">AMD</a>-sistemas de módulos baseados em <a href="https://requirejs.org/">RequireJS</a>, e mais recentemente <a href="https://webpack.github.io/">Webpack</a> e <a href="https://babeljs.io/">Babel</a>).</p>
<p>A boa notícia é que os navegadores modernos começaram a dar suporte nativamente à funcionalidade do módulo, e é sobre isso que este artigo trata. Isso só pode ser uma coisa boa - os navegadores podem otimizar o carregamento de módulos, tornando-o mais eficiente do que ter que usar uma biblioteca e fazer todo esse processamento extra no lado do cliente e viagens de ida e volta extras.</p>
<h2 id="Suporte_do_navegador">Suporte do navegador</h2>
<p>O uso de módulos JavaScript nativos depende do{{JSxRef("Statements/import", "import")}} e {{JSxRef("Statements/export", "export")}} afirmações; estes são suportados nos navegadores da seguinte maneira:</p>
<h3 id="importa">importa</h3>
<p>{{Compat("javascript.statements.import")}}</p>
<h3 id="exporta">exporta</h3>
<p>{{Compat("javascript.statements.export")}}</p>
<h2 id="Apresentando_um_exemplo">Apresentando um exemplo</h2>
<p>Para demonstrar o uso dos módulos, criamos um <a href="https://github.com/mdn/js-examples/tree/master/modules">conjunto simples de exemplos</a> que você pode encontrar no GitHub. Estes exemplos demonstram um conjunto simples de módulos que criam um<a href="/en-US/docs/Web/HTML/Element/canvas" title="Use the HTML <canvas> element with either the canvas scripting API or the WebGL API to draw graphics and animations."><code><canvas></code></a> em uma página da Web e desenhe (e relate informações sobre) formas diferentes na tela.</p>
<p>Estes são bastante triviais, mas foram mantidos deliberadamente simples para demonstrar claramente os módulos.</p>
<div class="blockIndicator note">
<p><strong>Nota: Se você deseja fazer o download dos exemplos e executá-los localmente, precisará executá-los por meio de um servidor da web local.</strong></p>
</div>
<h2 id="Exemplo_de_uma_estrutura_básica">Exemplo de uma estrutura básica</h2>
<p>No nosso primeiro exemplo (consulte <a href="https://github.com/mdn/js-examples/tree/master/modules/basic-modules">basic-modules</a>) nós temos uma estrutura de arquivos da seguinte maneira:</p>
<pre class="notranslate">index.html
main.js
modules/
canvas.js
square.js</pre>
<div class="blockIndicator note">
<p><strong>Nota: Todos os exemplos neste guia têm basicamente a mesma estrutura; o exposto acima deve começar a ficar bem familiar.</strong></p>
</div>
<p>Os dois módulos do diretório modules são descritos abaixo:</p>
<ul>
<li><code>canvas.js</code> — contém funções relacionadas à configuração da tela:
<ul>
<li><code>create()</code> — cria uma tela com uma largura e altura especificadas dentro de um invólucro <a href="/en-US/docs/Web/HTML/Element/div" title="The HTML Content Division element (<div>) is the generic container for flow content. It has no effect on the content or layout until styled using CSS."><code><div></code></a> com um ID especificado, que é anexado dentro de um elemento pai especificado. Retorna um objeto que contém o contexto 2D da tela e o ID do <a href="https://developer.mozilla.org/pt-BR/docs/Glossario/Wrapper">wrapper</a>.</li>
<li><code>createReportList()</code> — cria uma lista não ordenada anexada dentro de um elemento de wrapper especificado, que pode ser usado para gerar dados de relatório. Retorna o ID da lista.</li>
</ul>
</li>
<li><code>square.js</code> — contém:
<ul>
<li><code>name</code> — uma constante contendo a string 'square'.</li>
<li><code>draw()</code> — desenha um quadrado em uma tela especificada, com um tamanho, posição e cor especificados. Retorna um objeto que contém o tamanho, a posição e a cor do quadrado.</li>
<li><code>reportArea()</code> — grava a área de um quadrado em uma lista de relatórios específica, considerando seu tamanho.</li>
<li><code>reportPerimeter()</code> — grava o perímetro de um quadrado em uma lista de relatórios específica, considerando seu comprimento.</li>
</ul>
</li>
</ul>
<h2 id="Aside_—_.mjs_versus_.js">Aside — <code>.mjs</code> versus <code>.js</code></h2>
<p>Neste artigo, usamos extensões .js para nossos arquivos de módulo, mas em outros recursos você pode ver a extensão .mjs usada. <a href="https://v8.dev/features/modules#mjs">A documentação da V8 recomenda isso</a>, por exemplo. Os motivos apresentados são:</p>
<ul>
<li>É bom para maior clareza, ou seja, deixa claro quais arquivos são módulos e quais são JavaScript regulares.</li>
<li>Ele garante que seus arquivos de módulo sejam analisados como um módulo por tempos de execução, como <a href="https://nodejs.org/api/esm.html#esm_enabling">Node.js</a>, e construir ferramentas como <a href="https://babeljs.io/docs/en/options#sourcetype">Babel</a>.</li>
</ul>
<p>No entanto, decidimos continuar usando .js, pelo menos por enquanto. Para que os módulos funcionem corretamente em um navegador, você precisa garantir que seu servidor os esteja servindo com um cabeçalho Content-Type que contenha um tipo MIME JavaScript, como text / javascript. Caso contrário, você receberá um erro estrito de verificação do tipo MIME, de acordo com as linhas "O servidor respondeu com um tipo MIME não JavaScript" e o navegador não executará seu JavaScript. A maioria dos servidores já define o tipo correto para arquivos .js, mas ainda não para arquivos .mjs. Servidores que já veiculam arquivos .mjs incluem corretamente <a href="https://pages.github.com/">GitHub Pages</a> e <code><a href="https://github.com/http-party/http-server#readme">http-server</a></code> para Node.js.</p>
<p>Tudo bem se você já estiver usando esse ambiente ou se não estiver, mas souber o que está fazendo e tiver acesso (ou seja, você pode configurar o servidor para definir a configuração correta <code><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type">Content-Type</a></code> para arquivos <code>.mjs</code>). No entanto, isso pode causar confusão se você não controlar o servidor do qual está servindo arquivos ou publicar arquivos para uso público, como estamos aqui.</p>
<p>Para fins de aprendizado e portabilidade, decidimos manter o<code>.js</code>.</p>
<p>Se você realmente valoriza a clareza de usar .mjs para módulos versus usar .js para arquivos JavaScript "normais", mas não deseja se deparar com o problema descrito acima, sempre poderá usar .mjs durante o desenvolvimento e convertê-los em .js durante sua etapa de construção.</p>
<p>Também é importante notar que:</p>
<ul>
<li>Algumas ferramentas podem nunca suportar .mjs, como<a href="https://www.typescriptlang.org/">TypeScript</a>.</li>
<li>O atributo <code><script type="module"></code>é usado para indicar quando um módulo está sendo apontado, como você verá abaixo.</li>
</ul>
<h2 id="Exportando_recursos_do_módulo">Exportando recursos do módulo</h2>
<p>A primeira coisa que você faz para obter acesso aos recursos do módulo é exportá-los. Isso é feito usando o {{JSxRef("Statements/export", "export")}} declaração.</p>
<p>A maneira mais fácil de usá-lo é colocá-lo na frente de qualquer item que você queira exportar para fora do módulo, por exemplo:</p>
<pre class="brush: js; notranslate">export const name = 'square';
export function draw(ctx, length, x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, length, length);
return {
length: length,
x: x,
y: y,
color: color
};
}</pre>
<p>Você pode exportar funções, <code>var</code>, <code>let</code>, <code>const</code>, e — como veremos mais tarde - classes. Eles precisam ser itens de nível superior; você não pode usar a exportação dentro de uma função, por exemplo.</p>
<p>Uma maneira mais conveniente de exportar todos os itens que você deseja exportar é usar uma única instrução de exportação no final do arquivo do módulo, seguida por uma lista separada por vírgula dos recursos que você deseja exportar envoltos em chaves. Por exemplo:</p>
<pre class="brush: js; notranslate">export { name, draw, reportArea, reportPerimeter };</pre>
<h2 id="Importando_recursos_para_o_seu_script">Importando recursos para o seu script</h2>
<p>Depois de exportar alguns recursos do seu módulo, é necessário importá-los para o script para poder usá-los. A maneira mais simples de fazer isso é a seguinte:</p>
<pre class="brush: js notranslate">import { name, draw, reportArea, reportPerimeter } from './modules/square.js';</pre>
<p>Você usa o {{JSxRef("Statements/import", "import")}} , seguida por uma lista separada por vírgula dos recursos que você deseja importar agrupados em chaves, seguidos pela palavra-chave de, seguida pelo caminho para o arquivo do módulo - um caminho relativo à raiz do site, que para nossa <code>basic-modules</code> exemplo seria<code>/js-examples/modules/basic-modules</code>.</p>
<p>No entanto, escrevemos o caminho de maneira um pouco diferente - estamos usando a sintaxe de ponto (.) Para significar "o local atual", seguido pelo caminho além do arquivo que estamos tentando encontrar. Isso é muito melhor do que escrever todo o caminho relativo a cada vez, pois é mais curto e torna o URL portátil - o exemplo ainda funcionará se você o mover para um local diferente na hierarquia do site.</p>
<p>Então, por exemplo:</p>
<pre class="notranslate">/js-examples/modules/basic-modules/modules/square.js</pre>
<p>torna-se</p>
<pre class="notranslate">./modules/square.js</pre>
<p>Você pode ver essas linhas em ação em <code><a href="https://github.com/mdn/js-examples/blob/master/modules/basic-modules/main.js">main.js</a></code>.</p>
<div class="blockIndicator note">
<p><strong>Nota: Em alguns sistemas de módulos, você pode omitir a extensão do arquivo e o ponto</strong>(e.g. <code>'/modules/square'</code>). Isso não funciona nos módulos JavaScript nativos.</p>
</div>
<p>Depois de importar os recursos para o seu script, você pode usá-los exatamente como eles foram definidos no mesmo arquivo. O seguinte é encontrado em<br>
<code>main.js</code>, abaixo das linhas de importação:</p>
<pre class="brush: js; notranslate">let myCanvas = create('myCanvas', document.body, 480, 320);
let reportList = createReportList(myCanvas.id);
let square1 = draw(myCanvas.ctx, 50, 50, 100, 'blue');
reportArea(square1.length, reportList);
reportPerimeter(square1.length, reportList);
</pre>
<div class="blockIndicator note">
<p><strong>Nota: Embora os recursos importados estejam disponíveis no arquivo, eles são visualizações somente leitura do recurso que foi exportado. Você não pode alterar a variável importada, mas ainda pode modificar propriedades semelhantes à const. Além disso, esses recursos são importados como ligações ativas, o que significa que eles podem mudar de valor mesmo que você não possa modificar a ligação ao contrário de const.</strong></p>
</div>
<h2 id="Aplicando_o_módulo_ao_seu_HTML">Aplicando o módulo ao seu HTML</h2>
<p>Agora, apenas precisamos aplicar o módulo main.js. à nossa página HTML. Isso é muito semelhante ao modo como aplicamos um script regular a uma página, com algumas diferenças notáveis.</p>
<p>Primeiro de tudo, você precisa incluir <code>type="module"</code> no <a href="/en-US/docs/Web/HTML/Element/script" title="The HTML <script> element is used to embed or reference executable code; this is typically used to embed or refer to JavaScript code."><code><script></code></a> elemento, para declarar esse script como um módulo. Para importar o <code>main.js</code> script, usamos este:</p>
<pre class="brush: html; no-line-numbers notranslate"><script type="module" src="main.js"></script></pre>
<p>Você também pode incorporar o script do módulo diretamente no arquivo HTML, colocando o código JavaScript no corpo do elemento <script>:</p>
<pre class="brush: js notranslate"><script type="module">
/* JavaScript module code here */
</script></pre>
<p>O script para o qual você importa os recursos do módulo atua basicamente como o módulo de nível superior. Se você o omitir, o Firefox, por exemplo, exibirá um erro "SyntaxError: as declarações de importação podem aparecer apenas no nível superior de um módulo".</p>
<p>Você só pode usar <code>import</code> e <code>export</code> instruções dentro de módulos, não scripts regulares.</p>
<h2 id="Outras_diferenças_entre_módulos_e_scripts_padrão">Outras diferenças entre módulos e scripts padrão</h2>
<ul>
<li>Você precisa prestar atenção nos testes locais - se você tentar carregar o arquivo HTML localmente (i.e. com um arquivo<code>://</code> URL), você encontrará erros do CORS devido a requisitos de segurança do módulo JavaScript. Você precisa fazer seus testes através de um servidor.</li>
<li>Além disso, observe que você pode obter um comportamento diferente das seções de script definidas dentro dos módulos e não nos scripts padrão. Isso ocorre porque os módulos usam {{JSxRef("Strict_mode", "strict mode", "", 1)}} automaticamente.</li>
<li>Não há necessidade de usar o atributo deferir (consulte <a href="/en-US/docs/Web/HTML/Element/script#Attributes" title="The HTML <script> element is used to embed or reference executable code; this is typically used to embed or refer to JavaScript code."><code><script></code> attributes</a>) ao carregar um script de módulo; módulos são adiados automaticamente.</li>
<li>Os módulos são executados apenas uma vez, mesmo que tenham sido referenciados em várias tags <script>.</li>
<li>Por último, mas não menos importante, vamos esclarecer: os recursos do módulo são importados para o escopo de um único script - eles não estão disponíveis no escopo global. Portanto, você poderá acessar apenas os recursos importados no script para o qual eles foram importados e não poderá acessá-los no console JavaScript, por exemplo. Você ainda receberá erros de sintaxe mostrados no DevTools, mas não poderá usar algumas das técnicas de depuração que você esperava usar.</li>
</ul>
<h2 id="Exportações_padrão_versus_exportações_nomeadas">Exportações padrão versus exportações nomeadas</h2>
<p>A funcionalidade que exportamos até agora foi composta por <strong>named exports</strong> — cada item (seja uma função, const, etc.) foi referido por seu nome na exportação e esse nome também foi usado para se referir a ele na importação.</p>
<p>Há também um tipo de exportação chamado <strong>default export</strong> — isso foi projetado para facilitar a função padrão fornecida por um módulo e também ajuda os módulos JavaScript a interoperar com os sistemas de módulos CommonJS e AMD existentes (conforme explicado em <a href="https://hacks.mozilla.org/2015/08/es6-in-depth-modules/">ES6 In Depth: Modules</a> por Jason Orendorff; procure por "Exportações padrão").</p>
<p>Vejamos um exemplo ao explicar como ele funciona. Nos nossos módulos básicos <code>square.js</code> você pode encontrar uma função chamada <code>randomSquare()</code> que cria um quadrado com cor, tamanho e posição aleatórios. Queremos exportar isso como padrão, portanto, na parte inferior do arquivo, escrevemos isso:</p>
<pre class="brush: js; notranslate">export default randomSquare;</pre>
<p>Note a falta dos colchetes.</p>
<p>Em vez disso, poderíamos acrescentar <code>export default</code> na função e defina-a como uma função anônima, assim:</p>
<pre class="brush: js; notranslate">export default function(ctx) {
...
}</pre>
<p>No nosso arquivo main.js., importamos a função padrão usando esta linha:</p>
<pre class="brush: js; notranslate">import randomSquare from './modules/square.js';</pre>
<p>Isso ocorre porque há apenas uma exportação padrão permitida por módulo e sabemos que <em>randomSquare</em> é isso.</p>
<pre class="brush: js; notranslate">import {default as randomSquare} from './modules/square.js';</pre>
<div class="blockIndicator note">
<p><strong>Nota: A sintaxe as para renomear itens exportados é explicada abaixo no </strong><a href="#Renaming_imports_and_exports">Renaming imports and exports</a> seção.</p>
</div>
<h2 id="Evitando_conflitos_de_nomenclatura">Evitando conflitos de nomenclatura</h2>
<p>Até agora, nossos módulos de desenho de forma de tela parecem estar funcionando bem. Mas o que acontece se tentarmos adicionar um módulo que lide com o desenho de outra forma, como um círculo ou triângulo? Essas formas provavelmente teriam funções associadas, como <code>draw()</code>, <code>reportArea()</code>, etc. também; se tentássemos importar diferentes funções com o mesmo nome para o mesmo arquivo de módulo de nível superior, acabaríamos com conflitos e erros.</p>
<p>Felizmente, existem várias maneiras de contornar isso. Veremos isso nas próximas seções.</p>
<h2 id="Renomeando_importações_e_exportações">Renomeando importações e exportações</h2>
<p>Dentro dos colchetes da instrução de importação e exportação, você pode usar a palavra-chave junto com um novo nome de recurso, para alterar o nome de identificação que será usado para um recurso dentro do módulo de nível superior.</p>
<p>Por exemplo, os dois itens a seguir executariam o mesmo trabalho, embora de uma maneira ligeiramente diferente:</p>
<pre class="brush: js; notranslate">// inside module.js
export {
function1 as newFunctionName,
function2 as anotherNewFunctionName
};
// inside main.js
import { newFunctionName, anotherNewFunctionName } from './modules/module.js';</pre>
<pre class="brush: js; notranslate">// inside module.js
export { function1, function2 };
// inside main.js
import { function1 as newFunctionName,
function2 as anotherNewFunctionName } from './modules/module.js';</pre>
<p>Vejamos um exemplo real. Na nossa <a href="https://github.com/mdn/js-examples/tree/master/modules/renaming">renaming</a> diretório, você verá o mesmo sistema de módulos do exemplo anterior, exceto que adicionamos <code>circle.js</code> e <code>triangle.js</code> módulos para desenhar e relatar círculos e triângulos.</p>
<p>Dentro de cada um desses módulos, temos recursos com os mesmos nomes sendo exportados e, portanto, cada um tem o mesmo <code>export</code> declaração na parte inferior:</p>
<pre class="brush: js; notranslate">export { name, draw, reportArea, reportPerimeter };</pre>
<p>Ao importá-los para o main.js, se tentarmos usar</p>
<pre class="brush: js; notranslate">import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
import { name, draw, reportArea, reportPerimeter } from './modules/circle.js';
import { name, draw, reportArea, reportPerimeter } from './modules/triangle.js';</pre>
<p>O navegador geraria um erro como "SyntaxError: redeclaration of import name" (Firefox).</p>
<p>Em vez disso, precisamos renomear as importações para que sejam únicas:</p>
<pre class="brush: js; notranslate">import { name as squareName,
draw as drawSquare,
reportArea as reportSquareArea,
reportPerimeter as reportSquarePerimeter } from './modules/square.js';
import { name as circleName,
draw as drawCircle,
reportArea as reportCircleArea,
reportPerimeter as reportCirclePerimeter } from './modules/circle.js';
import { name as triangleName,
draw as drawTriangle,
reportArea as reportTriangleArea,
reportPerimeter as reportTrianglePerimeter } from './modules/triangle.js';</pre>
<p>Observe que você pode resolver o problema nos arquivos do módulo, e.g.</p>
<pre class="brush: js; notranslate">// in square.js
export { name as squareName,
draw as drawSquare,
reportArea as reportSquareArea,
reportPerimeter as reportSquarePerimeter };</pre>
<pre class="brush: js; notranslate">// in main.js
import { squareName, drawSquare, reportSquareArea, reportSquarePerimeter } from './modules/square.js';</pre>
<p>E funcionaria da mesma forma. Qual o estilo que você usa depende de você, no entanto, sem dúvida faz mais sentido deixar o código do módulo em paz e fazer as alterações nas importações. Isso faz especialmente sentido quando você está importando de módulos de terceiros sobre os quais você não tem controle.</p>
<p>24/5000</p>
<p>Criando um objeto de módulo</p>
<p>O método acima funciona bem, mas é um pouco confuso e longo. Uma solução ainda melhor é importar os recursos de cada módulo dentro de um objeto de módulo. O seguinte formulário de sintaxe faz isso:</p>
<pre class="brush: js; notranslate">import * as Module from './modules/module.js';</pre>
<p>Isso captura todas as exportações disponíveis no module.js e as torna disponíveis como membros de um objeto <code>Module</code>, efetivamente dando o seu próprio namespace. Então, por exemplo:</p>
<pre class="brush: js; notranslate">Module.function1()
Module.function2()
etc.</pre>
<p>Novamente, vejamos um exemplo real. Se você for ao nosso <a href="https://github.com/mdn/js-examples/tree/master/modules/module-objects">module-objects</a> diretório, você verá o mesmo exemplo novamente, mas reescrito para aproveitar essa nova sintaxe. Nos módulos, as exportações são todas da seguinte forma simples:</p>
<pre class="brush: js; notranslate">export { name, draw, reportArea, reportPerimeter };</pre>
<p>As importações, por outro lado, são assim:</p>
<pre class="brush: js; notranslate">import * as Canvas from './modules/canvas.js';
import * as Square from './modules/square.js';
import * as Circle from './modules/circle.js';
import * as Triangle from './modules/triangle.js';</pre>
<p>Em cada caso, agora você pode acessar as importações do módulo abaixo do nome do objeto especificado, por exemplo:</p>
<pre class="brush: js; notranslate">let square1 = Square.draw(myCanvas.ctx, 50, 50, 100, 'blue');
Square.reportArea(square1.length, reportList);
Square.reportPerimeter(square1.length, reportList);</pre>
<p>Agora você pode escrever o código da mesma forma que antes (contanto que inclua os nomes dos objetos quando necessário) e as importações sejam muito mais limpas.</p>
<h2 id="Módulos_e_classes">Módulos e classes</h2>
<p>Como sugerimos anteriormente, você também pode exportar e importar classes; essa é outra opção para evitar conflitos no seu código e é especialmente útil se você já tiver o código do módulo gravado em um estilo orientado a objetos.</p>
<p>Você pode ver um exemplo do nosso módulo de desenho de forma reescrito com as classes ES em nosso <a href="https://github.com/mdn/js-examples/tree/master/modules/classes">classes</a> diretório. Como exemplo, o <code><a href="https://github.com/mdn/js-examples/blob/master/modules/classes/modules/square.js">square.js</a></code> O arquivo agora contém todas as suas funcionalidades em uma única classe:</p>
<pre class="brush: js; notranslate">class Square {
constructor(ctx, listId, length, x, y, color) {
...
}
draw() {
...
}
...
}</pre>
<p>que exportamos então:</p>
<pre class="brush: js; notranslate">export { Square };</pre>
<p>No main.js, nós o importamos assim:</p>
<pre class="brush: js; notranslate">import { Square } from './modules/square.js';</pre>
<p>E então use a classe para desenhar nosso quadrado:</p>
<pre class="brush: js; notranslate">let square1 = new Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
square1.draw();
square1.reportArea();
square1.reportPerimeter();</pre>
<h2 id="Módulos_de_agregação">Módulos de agregação</h2>
<p>Haverá momentos em que você desejará agregar módulos. Você pode ter vários níveis de dependências, nos quais deseja simplificar as coisas, combinando vários submódulos em um módulo pai. Isso é possível usando a sintaxe de exportação dos seguintes formulários no módulo pai:</p>
<pre class="brush: js; notranslate">export * from 'x.js'
export { name } from 'x.js'</pre>
<p>Por exemplo, veja nosso <a href="https://github.com/mdn/js-examples/tree/master/modules/module-aggregation">module-aggregation</a> diretório. Neste exemplo (com base no exemplo de classes anteriores), temos um módulo extra chamado shapes.js, que agrega toda a funcionalidade de circle.js, square.js e triangle.js juntos. Também movemos nossos submódulos para dentro de um subdiretório dentro do diretório modules chamado shapes. Portanto, a estrutura do módulo neste exemplo é:</p>
<pre class="notranslate">modules/
canvas.js
shapes.js
shapes/
circle.js
square.js
triangle.js</pre>
<p>Em cada um dos submódulos, a exportação é da mesma forma, e.g.</p>
<pre class="brush: js; notranslate">export { Square };</pre>
<p>Em seguida, vem a parte de agregação. Dentro de shapes.js, incluímos as seguintes linhas:</p>
<pre class="brush: js; notranslate">export { Square } from './shapes/square.js';
export { Triangle } from './shapes/triangle.js';
export { Circle } from './shapes/circle.js';</pre>
<p>Eles capturam as exportações dos submódulos individuais e os disponibilizam efetivamente no módulo shapes.js.</p>
<div class="blockIndicator note">
<p><strong>Nota: As exportações mencionadas no shapes.js são basicamente redirecionadas pelo arquivo e realmente não existem nele, portanto, você não poderá escrever nenhum código relacionado útil dentro do mesmo arquivo.</strong></p>
</div>
<p>Portanto, agora no arquivo main.js., podemos obter acesso às três classes de módulos substituindo</p>
<pre class="brush: js; notranslate">import { Square } from './modules/square.js';
import { Circle } from './modules/circle.js';
import { Triangle } from './modules/triangle.js';</pre>
<p>com a seguinte linha única:</p>
<pre class="brush: js; notranslate">import { Square, Circle, Triangle } from './modules/shapes.js';</pre>
<h2 id="Carregamento_dinâmico_do_módulo">Carregamento dinâmico do módulo</h2>
<p>A parte mais recente da funcionalidade dos módulos JavaScript a estar disponível nos navegadores é o carregamento dinâmico de módulos. Isso permite que você carregue módulos dinamicamente somente quando eles forem necessários, em vez de precisar carregar tudo antecipadamente. Isso tem algumas vantagens óbvias de desempenho; vamos ler e ver como isso funciona.</p>
<p>Essa nova funcionalidade permite que você ligue {{JSxRef("Statements/import", "import()", "#Dynamic_Imports")}} como uma função, passando o caminho para o módulo como um parâmetro. Retorna um{{JSxRef("Promise")}}, que cumpre com um objeto de módulo (consulte <a href="#Creating_a_module_object">Creating a module object</a>) dando acesso às exportações desse objeto, e.g.</p>
<pre class="brush: js; notranslate">import('./modules/myModule.js')
.then((module) => {
// Do something with the module.
});</pre>
<p>Vejamos um exemplo. No <a href="https://github.com/mdn/js-examples/tree/master/modules/dynamic-module-imports">dynamic-module-imports</a> diretório, temos outro exemplo baseado em nosso exemplo de classes. Desta vez, no entanto, não estamos desenhando nada na tela quando o exemplo é carregado. Em vez disso, incluímos trêsbuttons — "Circle", "Square", e "Triangle" — que, quando pressionado, carrega dinamicamente o módulo necessário e, em seguida, usa-o para desenhar os shape.</p>
<p>Neste exemplo, fizemos apenas alterações em nossa <code><a href="https://github.com/mdn/js-examples/blob/master/modules/dynamic-module-imports/index.html">index.html</a></code> e <code><a href="https://github.com/mdn/js-examples/blob/master/modules/dynamic-module-imports/main.mjs">main.js</a></code> arquivos - as exportações do módulo permanecem as mesmas de antes.</p>
<p>No main.js, pegamos uma referência a cada botão usando um<a href="/en-US/docs/Web/API/Document/querySelector"><code>Document.querySelector()</code></a> chamada, por exemplo:</p>
<pre class="brush: js; notranslate">let squareBtn = document.querySelector('.square');</pre>
<p>Em seguida, anexamos um ouvinte de evento a cada botão para que, quando pressionado, o módulo relevante seja carregado dinamicamente e usado para desenhar a forma(shape):</p>
<pre class="brush: js; notranslate">squareBtn.addEventListener('click', () => {
import('./modules/square.js').then((Module) => {
let square1 = new Module.Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
square1.draw();
square1.reportArea();
square1.reportPerimeter();
})
});</pre>
<p>Observe que, como o cumprimento da promessa retorna um objeto de módulo, a classe é então transformada em uma sub-característica do objeto, portanto, agora precisamos acessar o construtor com <code>Module.</code> anexado a ele, e.g. <code>Module.Square( ... )</code>.</p>
<h2 id="Solução_de_problemas">Solução de problemas</h2>
<p>Aqui estão algumas dicas que podem ajudá-lo se você estiver com problemas para fazer seus módulos funcionarem. Sinta-se livre para adicionar à lista se descobrir mais!</p>
<ul>
<li>Mencionamos isso antes, mas para reiterar: arquivos<code>.js</code> precisa ser carregado com um tipo MIME de <code>text/javascript</code> (ou outro tipo MIME compatível com JavaScript, mas <code>text/javascript</code> é recomendável), caso contrário, você receberá um erro estrito de verificação do tipo MIME como "O servidor respondeu com um tipo MIME não JavaScript".</li>
<li>Se você tentar carregar o arquivo HTML localmente (i.e. com um arquivo<code>://</code> URL), você encontrará erros do CORS devido a requisitos de segurança do módulo JavaScript. Você precisa fazer seus testes através de um servidor. As páginas do GitHub são ideais, pois também servem arquivos .js com o tipo MIME correto.</li>
<li>Como .mjs é uma extensão de arquivo não padrão, alguns sistemas operacionais podem não reconhecê-lo ou tentar substituí-lo por outra. Por exemplo, descobrimos que o macOS estava adicionando silenciosamente .js ao final dos arquivos .mjs e ocultando automaticamente a extensão do arquivo. Então, todos os nossos arquivos foram lançados como x.mjs.js. Depois de desativarmos ocultar automaticamente as extensões de arquivo e treiná-lo para aceitar .mjs, tudo bem.</li>
</ul>
<h2 id="Veja_também">Veja também</h2>
<ul>
<li><a href="https://developers.google.com/web/fundamentals/primers/modules#mjs">Using JavaScript modules on the web</a>, por Addy Osmani e Mathias Bynens</li>
<li><a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/">ES modules: A cartoon deep-dive</a>, Postagem no blog Hacks por Lin Clark</li>
<li><a href="https://hacks.mozilla.org/2015/08/es6-in-depth-modules/">ES6 in Depth: Modules</a>, Publicação de blog de Hacks por Jason Orendorff</li>
<li>Livro de Axel Rauschmayer <a href="http://exploringjs.com/es6/ch_modules.html">Exploring JS: Modules</a></li>
</ul>
<p>{{Previous("Web/JavaScript/Guide/Meta_programming")}}</p>
|