Back-End

6 abr, 2017

Requisitando módulos Node.js a partir de namespaces de ClosureScript

Publicidade

O suporte ao módulo Node.js foi muito melhorado no futuro lançamento do compilador ClosureScript. Esse artigo explica como requisitar pacotes Node.js facilmente a partir de qualquer namespace do ClosureScript.

 

O que há de novo

O compilador ClosureScript adicionou suporte básico para a resolução de módulos Node.js na versão 1.9.456. No entanto, ele não permitia chamar esses módulos a partir dos namespaces do ClosureScript, dependendo, ao invés disso, de fontes JavaScript shim que importariam eles. A próxima versão do compilador corrige esse problema incluindo melhoras significativas de comportamento, tornando efetivamente possível chamar os módulos Node.js como se eles fossem namespaces regulares do ClosureScript.

Como nós fizemos isso funcionar

Para tornar tudo isso possível, uma nova opção de compilador foi lançada. Quando compilar seus projetos, o compilador ClosureScript agora lerá a opção :npm-deps e cuidará da instalação das dependências especificadas por você. Essa opção faz um mapeamento do nome do pacote até a versão. É evidente que você vai precisar ter tanto o Node.Js quanto o NPM instalados para que as dependências possam ser instaladas.

O que é melhor, não são necessárias mudanças nas ferramentas subsequentes. Os arquivos fonte do pacote NPM são processados e efetivamente se tornam bibliotecas externas, que tem sido suportadas há bastante tempo.

Exemplo:

Vamos analisar um exemplo específico: digamos que queremos utilizar uma biblioteca bem popular, a letf-pad em um projeto ClosureScript. Dada a seguinte estrutura de diretórios:

project
├─ src
│  ├─ example
│  │   └─ core.cljs

e nosso arquivo src/example/core.cljs,

;; src/example/core.cljs
(ns example.core
  (:require left-pad))

(enable-console-print!)

;; pad the number 42 with five zeros
(println (left-pad 42 5 0))

o seguinte script seria necessário para compilar esse projeto:

;; build.clj
(require '[cljs.build.api :as b])

(b/build "src"
  {:optimizations :none
   :main 'example.core
   :npm-deps {:left-pad "1.1.3"} ;; NEW
   :output-to "main.js"})

É interessante notar como o left-pad é tanto um namespace quanto uma função. Isso ocorre devido ao fato de ele ser a única exportação do módulo CommonJS left-pad. O suporte a essa resolução também é parte de um desenvolvimento recente no compilador ClosureScipt.

Se um módulo, por exemplo, o largamente utilizado pacote react, exportar um objeto, poderíamos referenciar as funções nesse objeto como se eles fossem variáveis em um namespace Closure(Script). Aqui está um exemplo:

(ns example.core
  (:require react))

;; react/DOM.div is equivalent to (react/createElement "div"), and that is
;; made clear in the h1 element.
(def title
  (react/DOM.div nil
    (react/createElement "h1" nil "Page title")))

Ainda tem mais

As bibliotecas ClosureScript empacotadas também são beneficiadas

As bibliotecas ClosureScript que empacotem dependências externas também podem se beneficiar dessas melhorias. O ticket CLJS-1973 adiciona suporte para a opção :npm-deps nos arquivos deps.cljs, permitindo que os autores de bibliotecas desenvolvam e distribuam bibliotecas que dependam diretamente dos módulos Node.js.

Isso não evita a necessidade dos pacotes externos

Mesmo que o compilador Google Closure agora possa consumir módulos Node.js, os pacotes externos ainda são muito necessários. Isso é consequência do fato de o compilador Google Closure não suportar muito da programação dinâmica empregada na escrita de alguns, se não da maioria, dos pacotes Node.js.

Felizmente, o compilador ClosureScript recentemente lançou a funcionalidade de interpretação de pacotes externos, o que torna muito mais fácil gerá-los a partir da interoperabilidade do JavaScript. Adicionalmente, o ClosureScript listará agressivamente todos os arquivos externos no classpath, então você ainda pode adicionar os pacotes CLJSJS e se beneficiar de seus arquivos externos, mesmo que você não precise dos namespaces que eles exportam.

A utilização dos módulos Node.js não é apenas para aplicativos Node.js

A utilização dos módulos Node.js pelo NPM não beneficia somente os projetos ClosureScript que sejam destinados para Node.js. O NPM é atualmente a maneira de utilizar pacotes JavaScript destinados aos navegadores. Isso significa que os aplicativos ClosureScript baseados nos navegadores também podem ser beneficiados por essa funcionalidade.

Eliminação de “Código Morto” nos módulos Node.js

Para mim, o maior benefício do novo módulo de suporte é a eliminação de “código morto” nessas bibliotecas (nem tanto) externas. Antes, as bibliotecas externas incluídas em um projeto ClosureScript somente seriam anexadas após a compilação do Google Closure. Por que o compilador Closure agora pode utilizar módulos Node.js, conseguimos a eliminação dos códigos não utilizados de maneira gratuita em nossas aplicações otimizadas!

Observações finais

Tem sido realmente gratificante trabalhar em melhorar o módulo de suporte ao Node.js no compilador ClosureScript. Minha esperança é que esses desenvolvimentos sigam um grande caminho para fechar os gargalos entre as bibliotecas ClosureScript e JavaScript publicadas no NPM.

Mais importante, eu acredito que o módulo de suporte ao Node.js melhorado tornará muito mais fácil manter as bases de código que compartilham tanto código ClosureScript quanto JavaScript, assim como tornar o ClosureScript mais atraente para os desenvolvedores JavaScript que dependam de pacotes publicados no NPM todos os dias.

Por favor, note que a utilização do módulo Node.js atualmente está em estado alpha. Todo o feedback será apreciado, e se você encontrar um problema, por favor, reporte no JIRA do ClosureScript.

***

António Monteiro faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://anmonteiro.com/2017/03/requiring-node-js-modules-from-clojurescript-namespaces/