用于复杂应用程序结构的 NodeJS 本地模块
Posted
技术标签:
【中文标题】用于复杂应用程序结构的 NodeJS 本地模块【英文标题】:NodeJS local modules for complex application structures 【发布时间】:2013-02-25 03:53:00 【问题描述】:我目前是使用 javascript 构建 Windows 8 应用程序的团队的一员。 我们正在使用 npm 和 browserify 来管理依赖项并将我们的模块转换为 AMD 浏览器友好的格式。
我们遇到的一个问题是疯狂的需要路径。这是因为我们的应用程序“组件”中有一个***文件夹。此文件夹包含一堆嵌套的 ui 组件/模块。这些模块有时需要 lib utils 和 helpers,它们位于 lib 目录中。
例如,位于“my/app/components/product/grid/item”中的模块可能需要位于“my/app/lib/helpers/view”的帮助模块。
require 路径有点疯狂而且非常丑陋: 要求("../../../../lib/helpers/view");
我们正在尽最大努力以模块化方式构建应用程序。现在我认为解决这个问题的正确方法是让我们的组件模块依赖于这些 util 辅助模块。我可以将 lib 助手放入他们自己的外部私有 git 存储库中,但这在让其他团队访问方面很痛苦(而且 git 私有存储库很慢)。另外,由于这些模块仅在应用程序中使用,因此进行更改、推送更改、然后返回应用程序和 npm 更新是浪费时间。这对某些人来说很好,但如果我们真的把它分解,它可能会很快变老。
我可以在组件 package.json 中执行 npm install "my/app/lib/helpers/view" 吗?但 npm install 不会自动为我们执行此操作。
我知道解决这个问题的其他一些方法(NODE_PATH,可能使用 npm install hook 或 npm preinstall 脚本),但想知道其他人是否有类似的问题和好的解决方案。
【问题讨论】:
我目前的方法是在构建时运行一个批处理脚本,为 NODE_PATH 设置环境变量。 好吧,多玩一些 npm 链接可能是这里的方法。我让我的应用程序模块有 package.json 文件,这些模块中的 npm 链接以使它们可用,然后从*** npm 链接它们。这里唯一糟糕的是我需要确保我们在全新安装时使用 npm 链接,因为 npm install 不会为我链接这些模块。 我认为单独的回购是要走的路。 尤其是像“帮手”这样的东西。 基本上每当你最终上一层时,你可能没问题,但如果你上了很多层,然后回到另一个目录树,你看到的东西应该是它自己的包裹。是否将其作为自己的存储库,或者使用@substack 推荐的签到node_modules
-technique,取决于您。
【参考方案1】:
您可以将您的"my/app/components/product/grid/item"
文件放入node_modules/grid/item.js
,然后当您在应用程序代码中使用require('grid/item')
时,您将使用更简洁的require 路径语法获得您想要的文件。只需将node_modules/grid/item.js
和其他任何文件检查到 git 中即可。 node_modules/
目录甚至不需要位于顶层,因为 node 和 browserify 使用的 require 算法将从当前路径一直搜索 node_modules/
目录到 /
直到找到匹配的模块。
只需确保将 "grid"
添加到您的 package.json 中的 "bundledDependencies"
数组中,这样您就不会意外在其上安装一些东西。
你可以阅读更多关于checking node modules into git的信息。
阅读browserify handbook about avoiding ../../../../../../部分了解更多信息。
NODE_PATH 总是一个坏主意,browserify 不支持它。永远不要使用它。
【讨论】:
有趣。我知道 NODE_PATH 不是最好的方法,但我最近用 express 观看了 TJ 关于模块化 Web 应用程序 (tjholowaychuk.com/post/38571504626/…) 的视频,他提到使用 NODE_PATH。 是的,我们是 git ignore node_modules/*,但我认为 shrinkwrap 会锁定所有依赖项,甚至是依赖项的依赖项。那篇文章似乎没有提到这个事实。 我宁愿不把这些放在顶层,所以就像你提到的那样,我可能会创建一个目录结构,其中顶层 node_modules 用于第 3 方,然后在我的 lib 文件夹中,可能有 node_modules 用于应用程序本地模块。我想我对这种方法的问题是你必须有一个本地模块的平面列表。 是的,但是在这种情况下,子堆栈似乎 Browserify 不会转换原始源文件,如 JSX 或 CoffeeScript。如何以这种方式要求 jsx 文件? 你说 NODE_PATH 是个坏主意。能详细点吗?【参考方案2】:您可以做的一件事是在您的需求配置中为您的助手创建一个别名...
require.config(
paths:
"helpers": "my/app/lib/helpers"
);
这会减少你的一些漫长的道路。
【讨论】:
是的,我认为这只是我们没有使用的前 requirejs。见上文,我们使用 browserify 来包装我们的模块。另外,我希望这个解决方案也可以在服务器上运行。【参考方案3】:require() 函数的问题是路径是相对于当前文件的。您可以将模块放在 node_modules 目录中,但这是您能做的最糟糕的事情。 node_modules 是所有第三方模块所在的目录。如果您遵循这个简单的规则,那么始终保持最新是非常容易和方便的,您可以删除所有依赖项(删除 node_modules)并执行npm install
。
最好的解决方案是定义自己的 require 函数并使其全局化。例如:
你的项目结构是:
my-project
| tools
|- docs
|- logs
|- conf
`- src
|- node_modules
|- package.json
|- mod.js
|- a
| `- b
| `- c.js
`- d
`- app.js
mod.js
global.mod = function (file)
return require ("./" + file);
;
app.js
//This should be the first line in your main script
require ("../mod");
//Now all the modules are relative from the `src` directory
//You want to use the a/b/c.js module
var c = mod ("a/b/c");
就是这样,很简单。如果要获取位于 node_modules 中的第三方模块,请使用 require()。如果您想获得自己的模块,请使用 mod()。
请记住,node_modules 仅适用于第三方模块,规则 nº1。
【讨论】:
像您在require("./" + file)
中使用的自定义 require 函数不是静态可分析的,并且不适用于 browserify。将您自己的模块放入node_modules/
是完全可以接受的,这也是为什么首先出现"bundledDependencies"
这样的东西的原因。
如果它与 browserify 不兼容,则使其与 browserify 兼容。我的解决方案比把你的东西放在 node_modules 中更干净以上是关于用于复杂应用程序结构的 NodeJS 本地模块的主要内容,如果未能解决你的问题,请参考以下文章
使用本地 npm 依赖项设置 docker nodejs 应用程序