87

I have several apps in node that all share a few modules that I've written. These modules are not available via npm. I would like to be able to share freely between apps, but I don't want to copy directories around, nor rely on Git to do so. And I'm not really big on using symlinks to do this either.

I would like to arrange directories something like this:

app1
 server.js
 node_modules
  (public modules from npm needed for app1)
 lib
  (my own modules specific to app1)

app2
 server.js
 node_modules
  (public modules from npm needed for app2)
 lib
  (my own modules specific to app2)

shared_lib
 (my own modules that are used in both app1 and app2)

The problem I'm seeing is that the modules in shared_lib seem to get confused as to where to find the modules that will be in the node_modules directory of whichever app they are running in. At least I think that is the problem.

So....what is a good way to do this that avoids having duplicates of files? (note that I don't care about duplicates of things in node_modules, since those aren't my code, I don't check them into Git, etc)

4

6 回答 6

52

npm 文档建议使用npm-link在本地创建您自己的 Node.js 包,然后将它们提供给其他 Node.js 应用程序。这是一个简单的四步过程。

一个典型的过程是首先创建一个具有以下结构的包:

  hello
  | index.js
  | package.json

这些文件的典型实现是:

index.js

  exports.world = function() {
     return('Hello World');
  }

包.json

  {
    "name": "hello",
    "version": "0.0.1",
    "private": true,
    "main": "index.js",
    "dependencies": {
    },
    "engines": {
    "node": "v0.6.x"
    }
  }

"private:true" 确保 npm 将拒绝发布包。这是一种防止意外发布私有包的方法。

接下来,导航到 Node.js 包文件夹的根目录并运行npm link以全局链接包,以便它可以在其他应用程序中使用。

要在另一个应用程序中使用这个包,例如“hello-world”,具有以下目录结构:

 hello-world
 | app.js

导航到 hello-world 文件夹并运行:

 npm link hello

现在您可以像使用任何其他 npm 包一样使用它,如下所示:

应用程序.js

  var http = require('http');
  var hello = require('hello');

  var server = http.createServer(function(req, res) {
     res.writeHead(200);
     res.end(hello.world());
  });
  server.listen(8080);
于 2012-07-01T03:20:21.000 回答
25

我通过在不同级别设置node_modules文件夹来完成这项工作 - 节点然后自动向上遍历,直到找到模块。

请注意,您不必发布到 npm 就可以在 node_modules 中有一个模块 - 只需使用:

"private": true

在您的每个私有package.json文件中 - 对于您的项目,我将拥有以下内容:

app1
 server.js
 node_modules
  (public modules from npm needed for app1)
  (private modules locally needed for app1)

app2
 server.js
 node_modules
  (public modules from npm needed for app2)
  (private modules locally needed for app2)

node_modules
  (public modules from npm needed for app1 & app2)
  (private modules locally for app1 & app2)

关键是 node.js 已经有一种机制来处理这个问题,而且非常棒。只需将它与“private not on NPM”技巧结合起来,你就可以开始了。

简而言之:

require('somemodule')

从应用程序 A 或 B 将向上级联,直到找到模块 - 无论它是生活在低处还是高处。确实 - 这使您可以在不更改任何require(...)语句的情况下热交换位置。

node.js 模块文档

于 2012-07-01T13:04:08.317 回答
5

只需在 require 调用中使用正确的路径

例如在 server.js 中是:

var moduleName = require('../shared_lib/moduleName/module.js');

重要的是要知道,只要您的路径以“/”、“../”或“./”为前缀,路径就相对于调用文件。

有关节点模块加载的更多信息,请访问: http ://nodejs.org/docs/latest/api/modules.html

于 2012-07-01T01:47:34.353 回答
4

是的,您可以从 app1 引用 shared_lib,但是如果您想将 app1 打包并部署到其他环境(例如 AWS 上的 Web 服务器),则会遇到问题。

在这种情况下,您最好使用“npm install shared_lib/module”将 shared_lib 中的模块安装到 app1 和 app2。它还将在 app1 和 app2 中安装 shared_lib 模块的所有依赖项并处理冲突/重复。

请参阅: 如何在没有我自己的注册表的情况下安装私有 NPM 模块?

于 2017-01-13T10:45:36.047 回答
2

如果您查看node.js 文档,您会发现 Node.js 也理解package.json文件格式,至少粗略理解。

基本上,如果您有一个名为 的目录foo,并且该目录中有一个package.json带有键值对的文件:"main": "myCode.js",那么如果您尝试require("foo")找到该目录并在其中找到一个package.json文件,那么它将foo/myCode.js用于foo模块。

因此,对于您的目录结构,如果每个共享库都有自己的目录,其中包含这样一个简单的package.json文件,那么您的应用程序可以通过以下方式获取共享库:

var lib1 = require('../shared_lib/lib1');
var lib2 = require('../shared_lib/lib2');

这应该适用于这两个应用程序。

于 2012-07-01T01:39:37.107 回答
0

另一种解决方案是将其他地方的文件克隆到这个 repo 中:

克隆.js

const path = require('path')
const fs = require('fs')

const shared = [
  {
    type: 'file',
    source: '../app1',
    files: [
      'src/file1',
      'src/file2',
      '...'
    ],
  },
]

function cloneFiles(source, files) {
  const Reset = '\x1b[0m'
  const FgGreen = '\x1b[32m'
  console.log(`---------- Cloning ${files.length} files from ${source} ----------`)

  for (const file of files) {
    const sourceFile = path.join(__dirname, '..', source, file)
    const targetFile = path.join(__dirname, '..', file)

    process.stdout.write(` ${file} ... `)
    fs.copyFileSync(sourceFile, targetFile)
    console.log(`${FgGreen}Done!${Reset}`)
  }

  console.log(`---------- All done successfully ----------\n`)
}

;(() => {
  for (const item of shared) {
    switch (item.type) {
      case 'file':
        cloneFiles(item.source, item.files)
        break
    }
  }
})()

然后,在package.json中,您可以添加此脚本并在您想要克隆/同步文件时调用它:

"clone": "node clone.js"
于 2022-02-18T05:41:41.850 回答