在过去的三四年中,使用PHP进行编程时,我使用composer
来管理应用程序依赖项。 现在需要切换到nodejs
,并因此配置一个熟悉的开发环境。 幸运的是,我使用了PhpStorm IDE,它允许您同时使用PHP和JS。 我参与的项目的一个特点是多模块化。 在模块之间划分功能的目的不是为了重用,而是由于分解成松散耦合的组件而降低了应用程序的最终复杂性。 通常,在解决一个问题的框架内对多个模块进行更改并提交给多个存储库的情况下,这些项目是正常的。

在设置nodejs
项目时,我遇到了一些使多模块开发复杂化的功能。 该出版物诞生于尝试处理这些功能的过程中。 削减nodejs
,PHP着眼于部署nodejs
项目。
示范项目结构
该项目包含3个模块:
- 应用 :头模块连接依赖项;
- 功能模块 :包含从头模块调用的功能;
- 基本模块 :包含从功能模块调用的功能;

每个模块的代码位于github上:
各个依赖项管理器( composer.json
和package.json
)的模块描述符位于每个模块中,即每个模块都可以扩展为php模块和js模块。 模块中的PHP代码和JS代码可以简单地并排放置,而不会相互交叉。
运行应用程序以执行:
$ php index.php $ nodejs index.js
两种情况下的工作结果:
This is application. This is func module. This is base module.
目标
工作环境中的项目应允许:
- 跟踪IDE中涉及开发的每个模块中的更改;
- 使用IDE,只需一次操作即可将更改提交到不同的存储库。
- 使用调试器跟踪模块代码的执行;
通过composer
部署
这里的一切都很熟悉。 在应用程序的部署描述符( composer.json )中,使用模块指定存储库的地址,并将模块的主分支规定为具有所需版本的依赖项:
{ "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" } ] }
执行命令后:
$ composer install
带有模块的./vendor
出现在./vendor
目录中,该目录又包含.git
目录:
./vendor/
./flancer64/
./habr-cvsn-mod-base/
./habr-cvsn-mod-base/
即, composer
立即以适合于开发(版本控制)的形式部署依赖项。 仅需配置PhpStorm IDE(在版本控制下放置依赖模块):

您可以跟踪所有已开发模块中的更改:

并同时将所有更改提交到本地存储库:

并推送到远程:

调试也没有问题。 我们可以在基本模块代码的任何行上设置断点-在调试器下启动应用程序后,在需要的地方发生断点:

一般来说,在平常的环境中,舒适如拖鞋。
通过npm正常部署
与composer
不同composer
npm
并不假定项目中的node_modules
目录中的任何模块都可能受版本控制。 我们可以在部署描述符package.json中指定应从外部存储库(例如,从githib)加载模块:
{ "dependencies": { "habr-cvsn-mod-base": "github:flancer64/habr-cvsn-mod-base", "habr-cvsn-mod-func": "github:flancer64/habr-cvsn-mod-func" } }
但是我们没有选择让npm
为加载的模块创建本地存储库( .git
子目录)。
执行命令后:
$ npm install
依赖项是在本地下载和安装的,无法使用版本控制:

(缺少./.git/
中的子目录./node_modules/habr-cvsn-mod-base/
)
但是调试器将在基本模块中停止运行而不会出现问题:

使用链接选项通过npm进行部署
为了使./node_modules/
中的模块可以保持在版本控制下, npm
开发人员建议使用' link '选项。 简而言之,该方法的本质是将需要版本控制的模块克隆到开发人员磁盘上的任意位置(例如,在/home/alex/work/habr/
),然后链接到/usr/lib/node_modules/
使用命令:
# npm link
(我需要root特权才能执行)
之后,您已经可以在项目中使用以下命令:
$ npm link habr-cvsn-mod-base $ npm link habr-cvsn-mod-func
npm
将在/usr/lib/node_modules/
找到适当的模块,并关闭./node_modules/
项目中与其对应的子目录:
$ 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
/usr/lib/node_modules/
本身中的模块又是指向模块原始位置的链接:
$ 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 ...
在“永久注册”中,“注册”包含一个本地存储库:
$ ls -lha /home/alex/work/habr/habr-cvsn-mod-base ... drwxrwxr-x 8 alex alex 4,0K jūl 2 16:18 .git ...
因此,我们可以配置IDE来控制项目依赖项中的更改:

当您尝试运行应用程序时,问题开始了:
$ 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) ...
应用程序可以看到链接的功能模块,但是功能模块本身看不到链接的基本模块。 要退出这种情况, 请对nodejs
使用--preserve-symlinks键 :
$ nodejs --preserve-symlinks index.js
将密钥添加到IDE中的项目启动命令中:

现在启动已通过,但是调试存在问题-依赖项中的断点无法解决。 您可以停在head模块中,然后转到依赖源的步骤,但是IDE PhpStorm在运行时不会看到断点本身,尽管它会显示:

IDE开发人员说它应该可以,但是不起作用(刷新缓存,IDE重新启动)。
通常,此出版物的目的是采访js同事在类似情况下如何脱身,但是在撰写本文的过程中,该项目的开发又出现了另一种组合:
将源代码放置在npm-project的内部目录中
事实证明,如果要进行链接,请使用composer
在./vendor/
子目录中创建的来自github的模块的克隆,而不是绑定到项目外部的目录,则js脚本无需--preserve-symlinks
即可运行,并且对我来说更重要的是,PhpStorm IDE可以看到模块内部的断点。 因为 仅将composer
仅用于克隆项目模块是没有意义的,我使用了常规的git
并将模块的源代码克隆到./own_modules
子目录中。 然后他重复了上一段的操作:
- 将子目录
./own_modules/...
的模块与系统库/usr/lib/node_modules/
; - 将系统库中的模块与项目连接;
- 将PhpStorm IDE配置为与
./own_modules/
子目录中的本地存储库一起使用;

我不知道是什么原因,但是当从属模块的源位于项目内部时,程序集的最终结果与从属模块的源位于项目外部的目录中时大不相同。
总结
比较构建多模块应用程序的两种方法(带有composer
PHP和带有npm
JS),我可以得出结论,与npm
, composer
对开发人员更友好。 composer
者开发人员(2012年npm
)可能考虑了npm
开发人员(2010年npm
)的经验。 但是,通过一些额外的努力, npm
还提供了在相当舒适的条件下开发多模块应用程序的机会。
用于以各种模式进行项目部署的命令脚本: