Nos últimos três ou quatro anos, ao programar em PHP, usei o composer
para gerenciar dependências de aplicativos. Agora, é necessário alternar para o nodejs
e, como resultado, configurar um ambiente de desenvolvimento familiar. Felizmente, eu uso o PhpStorm IDE, que permite trabalhar com PHP e JS. Uma característica dos projetos nos quais participo é a multi-modularidade. A funcionalidade é dividida entre os módulos, não tanto para reutilização, como para reduzir a complexidade final do aplicativo devido à decomposição em componentes fracamente acoplados. Em geral, é normal para esses projetos quando, na estrutura de solução de um problema, são feitas alterações em vários módulos e comprometidas em vários repositórios.

Ao configurar um projeto nodejs
, deparei-me com alguns recursos que complicam o desenvolvimento de vários módulos. Esta publicação nasceu no processo de tentar lidar com esses recursos. Sob o corte, a visão do PHP de implantar um projeto nodejs
.
Estrutura do projeto de demonstração
O projeto consiste em 3 módulos:
- aplicação : módulo principal conectando dependências;
- módulo funcional : contém funções chamadas do módulo principal;
- módulo base : contém funções chamadas de um módulo de função;

O código para cada módulo está localizado no github:
Os descritores do módulo para os respectivos gerenciadores de dependência ( composer.json
e package.json
) estão localizados em cada módulo, ou seja, cada módulo pode ser expandido como um módulo php e como um módulo js. Os códigos PHP e JS nos módulos são simplesmente colocados lado a lado, sem se cruzarem.
Executando o aplicativo para execução:
$ php index.php $ nodejs index.js
O resultado do trabalho em ambos os casos:
This is application. This is func module. This is base module.
Objetivos
Um projeto em um ambiente de trabalho deve permitir:
- acompanhar as alterações do IDE em cada módulo envolvido no desenvolvimento;
- Usando o IDE, confirme as alterações em diferentes repositórios em uma única ação.
- use o depurador para rastrear a execução do código dos módulos;
Implantação através do composer
Tudo é familiar aqui. No descritor de implementação ( composer.json ) do aplicativo, especifique os endereços dos repositórios com os módulos e prescreva as ramificações principais dos módulos como dependências com a versão desejada:
{ "require": { "flancer64/habr-cvsn-mod-base": "dev-master as 0.1.0", "flancer64/habr-cvsn-mod-func": "dev-master as 0.1.0" }, "repositories": [ { "type": "vcs", "url": "https://github.com/flancer64/habr-cvsn-mod-base" }, { "type": "vcs", "url": "https://github.com/flancer64/habr-cvsn-mod-func" } ] }
Depois de executar o comando:
$ composer install
./vendor
com módulos aparecem no diretório ./vendor
, que por sua vez contém os diretórios .git
:
./vendor/
./flancer64/
./habr-cvsn-mod-base/
./habr-cvsn-mod-base/
Ou seja, o composer
implanta imediatamente as dependências em um formato adequado para desenvolvimento (controle de versão). Resta apenas configurar o PhpStorm IDE (coloque os módulos dependentes sob controle de versão):

e você pode acompanhar as alterações em todos os módulos desenvolvidos:

e confirme todas as alterações nos repositórios locais ao mesmo tempo:

e pressione para o controle remoto:

Depuração também não é problema. Podemos definir pontos de interrupção em qualquer linha do código do módulo base - após iniciar o aplicativo no depurador, a interrupção ocorre quando necessário:

Em geral, o ambiente usual, confortável como chinelos.
Implantação normal por npm
Ao contrário do composer
npm
não assume que no projeto quaisquer módulos do diretório node_modules
possam estar sob controle de versão. Podemos especificar no descritor de implantação package.json que o módulo deve ser carregado de um repositório externo (por exemplo, do githib):
{ "dependencies": { "habr-cvsn-mod-base": "github:flancer64/habr-cvsn-mod-base", "habr-cvsn-mod-func": "github:flancer64/habr-cvsn-mod-func" } }
mas não temos a opção de o npm
criar um repositório local para o módulo carregado (subdiretório .git
).
Depois de executar o comando:
$ npm install
as dependências são baixadas e instaladas localmente, sem a possibilidade de usar o controle de versão:

(subdiretório ausente ./.git/
em ./node_modules/habr-cvsn-mod-base/
)
Mas o depurador para no módulo base sem problemas:

Implantar via npm usando a opção de link
Para que os módulos de ./node_modules/
possam ser mantidos sob controle de versão, os desenvolvedores do npm
sugerem o uso da opção ' link '. Em resumo, a essência da abordagem é que os módulos que precisam ser versionados são clonados em um local arbitrário no disco do desenvolvedor (por exemplo, em /home/alex/work/habr/
) e, em seguida, vinculados a /usr/lib/node_modules/
usando o comando:
# npm link
(Eu precisava de privilégios de root para executar)
Depois disso, você já pode usar os comandos no projeto:
$ npm link habr-cvsn-mod-base $ npm link habr-cvsn-mod-func
npm
encontrará os módulos apropriados em /usr/lib/node_modules/
e fechará os subdiretórios correspondentes do projeto ./node_modules/
para eles:
$ ls -lh ./node_modules/ total 0 lrwxrwxrwx 1 alex alex 57 jūl 2 16:18 habr-cvsn-mod-base -> ../../../../../../usr/lib/node_modules/habr-cvsn-mod-base lrwxrwxrwx 1 alex alex 57 jūl 2 16:18 habr-cvsn-mod-func -> ../../../../../../usr/lib/node_modules/habr-cvsn-mod-func
Os módulos em /usr/lib/node_modules/
próprios, por sua vez, são links para o local original dos módulos:
$ ls -lh /usr/lib/node_modules/ ... lrwxrwxrwx 1 root root 39 jūl 2 16:18 habr-cvsn-mod-base -> /home/alex/work/habr/habr-cvsn-mod-base lrwxrwxrwx 1 root root 39 jūl 2 16:18 habr-cvsn-mod-func -> /home/alex/work/habr/habr-cvsn-mod-func ...
E em seu lugar permanente, "registration" contém um repositório local:
$ ls -lha /home/alex/work/habr/habr-cvsn-mod-base ... drwxrwxr-x 8 alex alex 4,0K jūl 2 16:18 .git ...
Assim, podemos configurar o IDE para controlar alterações nas dependências do projeto:

Os problemas começam quando você tenta executar o aplicativo:
$ nodejs index.js internal/modules/cjs/loader.js:670 throw err; ^ Error: Cannot find module 'habr-cvsn-mod-base' at Function.Module._resolveFilename (internal/modules/cjs/loader.js:668:15) at Function.Module._load (internal/modules/cjs/loader.js:591:27) at Module.require (internal/modules/cjs/loader.js:723:19) at require (internal/modules/cjs/helpers.js:14:16) at Object.<anonymous> (/home/alex/work/habr/habr-cvsn-mod-func/src/index.js:3:14) ...
O aplicativo vê o módulo funcional vinculado, mas o próprio módulo funcional não vê o módulo básico vinculado. Para sair da situação, use a chave --preserve-symlinks para nodejs
:
$ nodejs --preserve-symlinks index.js
Adicione a chave ao comando de inicialização do projeto no IDE:

Agora o lançamento passa, mas há problemas com a depuração - os pontos de interrupção nas dependências não funcionam. Você pode parar no módulo principal e seguir as etapas para as fontes de dependência, mas o IDE PhpStorm não vê o próprio ponto de interrupção em tempo de execução, embora exiba:

Os desenvolvedores de IDE dizem que deve funcionar, mas não funciona (o cache liberado, o IDE reiniciado).
Em geral, o objetivo desta publicação era entrevistar os colegas como eles se saem em uma situação semelhante, mas no processo de redação do artigo surgiu outra combinação para o desenvolvimento do projeto:
Colocação de códigos-fonte em diretórios internos do projeto npm
Verificou-se que, para vincular, você usa clones de módulos do github criados pelo composer
no subdiretório ./vendor/
, em vez de estarem vinculados a diretórios externos ao projeto, os scripts js são executados sem a --preserve-symlinks
e, mais importante para mim, o PhpStorm IDE vê pontos de interrupção dentro dos módulos. Porque não faz sentido usar o composer
apenas para clonar módulos do projeto, usei o git
usual e clonei o código-fonte dos módulos no subdiretório ./own_modules
. Então ele repetiu as manipulações do parágrafo anterior:
- vinculou os módulos no subdiretório
./own_modules/...
à biblioteca do sistema /usr/lib/node_modules/
; - módulos conectados na biblioteca do sistema com o projeto;
- Configurou o PhpStorm IDE para trabalhar com repositórios locais no subdiretório
./own_modules/
;

Não sei qual é o motivo, mas quando as fontes dos módulos dependentes estão dentro do projeto, o resultado final da montagem é significativamente diferente de quando as fontes dos módulos dependentes estão em um diretório externo ao projeto.
Sumário
Comparando as duas abordagens para a construção de aplicativos multi-módulo (PHP com composer
e JS com npm
), posso concluir que o composer
mais amigável ao desenvolvedor que o npm
. É possível que os desenvolvedores do composer
(primeira versão em 2012) tenham levado em conta a experiência dos desenvolvedores npm
(primeira versão em 2010). No entanto, com algum esforço adicional, o npm
também oferece a oportunidade de desenvolver aplicativos com vários módulos em condições razoavelmente confortáveis.
Scripts de comando para implantação do projeto em vários modos: