如何使node.js要求绝对?(而不是亲戚)


234

我想始终通过项目的根目录而不是相对于当前模块来要求文件。

例如,如果您查看https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js第6行,您将看到

express = require('../../')

这真是糟糕的IMO。想象一下,我只想将我所有的示例都更接近根源。那将是不可能的,因为我将不得不在每个示例中多次更新30多个示例。对此:

express = require('../')

我的解决方案是对基于root的情况有一种特殊情况:如果字符串以$开头,则它相对于项目的根文件夹。

任何帮助表示赞赏,谢谢

更新2

现在,我正在使用require.js,它允许您以一种方式编写并在客户端和服务器上均可使用。Require.js还允许您创建自定义路径。

更新3

现在,我移至webpack + gulp,并使用Enhanced-require处理服务器端的模块。请参阅此处的基本原理:http : //hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/


如果您决定使用显式的根路径常量/变量,则此答案适用于。该解决方案使用一个微小的github模块来确定根路径。
蒸汽动力

Answers:


162

然后呢:

var myModule = require.main.require('./path/to/module');

它需要的文件就好像是从主js文件中获取的文件一样,因此只要您的主js文件位于项目的根目录下,它就可以很好地工作……这是我的感谢。


这不是一个坏主意(:然后,您可以定义一些其他方法来以某种方式重新映射您的require.main模块中的应用程序。我认为您可以做到require.main.req('client / someMod')。比我当前的requirejs更冗长。我也不认为这是值得的,因为我也不喜欢browserify,因为更改不是立即发生的并且丢失更改(因为我的代码应同时在浏览器和node.js中运行)
Totty.js

4
如果发现它太冗长,只需使用.bind():var rootReq = require.bind(require.main); rootReq('./path/to/module');
cronvel 2014年

是的,这对于仍想在客户端使用browserify的人很有用。对我而言,不再需要了,但是无论如何都要感谢您的回答(:
Totty.js 2014年

6
如果主要是您的计划的根本:)
亚历山大·米尔斯

12
如果代码包含单元测试(例如Mocha test
alx lark)在

129

Browserify手册中有一个非常有趣的部分:

避免../../../../../../ ..

并非应用程序中的所有内容都正确属于公共npm,并且在许多情况下,设置私有npm或git repo的开销仍然很大。这里有一些避免 ../../../../../../../相对路径问题的方法。

node_modules

人们有时会反对将特定于应用程序的模块放入node_modules中,因为在不从npm检入第三方模块的情况下,如何检入内部模块并不明显。

答案很简单!如果您有一个.gitignore忽略的文件node_modules

node_modules

您可以!为每个内部应用程序模块添加一个例外:

node_modules/*
!node_modules/foo
!node_modules/bar

请注意,你不能屏蔽的子目录,如果父已被忽略。所以,不是忽略的node_modules,你必须忽略每一个目录 node_modulesnode_modules/*技巧,然后您可以添加您的例外。

现在,在应用程序中的任何位置,您都可以拥有require('foo')require('bar')不拥有非常大且脆弱的相对路径。

如果你有很多的模块,并希望让他们从NPM安装的第三方模块更独立的,你可以把它们放在一个目录下node_modules,例如node_modules/app

node_modules/app/foo
node_modules/app/bar

现在,您将能够require('app/foo')require('app/bar') 在应用程序的任何地方。

在您的中.gitignore,只需添加一个例外node_modules/app

node_modules/*
!node_modules/app

如果您的应用程序在package.json中配置了转换,则您需要在您node_modules/foo或您的node_modules/app/foo组件目录中创建一个单独的package.json及其自己的转换字段,因为转换不会跨模块边界应用。这将使您的模块对应用程序中的配置更改更健壮,并且更容易在应用程序外部独立地重用软件包。

符号链接

如果您正在开发可以进行符号链接而不需要支持Windows的应用程序,则另一个方便的技巧是将lib/app/文件夹符号链接到中node_modules。在项目根目录中,执行以下操作:

ln -s ../lib node_modules/app

现在,您可以从项目中的任何位置lib/通过require('app/foo.js')获取获取文件lib/foo.js

自定义路径

您可能会看到一些地方谈论使用$NODE_PATH 环境变量或opts.paths为节点添加目录,并通过浏览器查找来查找模块。

与大多数其他平台不同,$NODE_PATH与有效使用node_modules目录相比,在节点中使用带有路径目录的外壳样式数组的效果不佳。

这是因为您的应用程序与运行时环境配置之间的联系更加紧密,因此有更多的活动部件,并且您的应用程序只有在正确设置环境后才能运行。

node和browserify都支持,但不鼓励使用 $NODE_PATH


17
将其放入node_modules文件夹的唯一不足之处在于,它使核对(rm -rf node_modules)文件夹变得更加困难
Michael

13
@Michael没那么难:git clean -dx node_modules
Peter Wilkinson

3
或者,如果您忘记了git clean语法,则始终可以rm -rf node_modules && git checkout node_modules-确保子目录git stash有任何更改node_modules
derenio

1
我喜欢使用node_modules的想法,但考虑到它的易失性,不喜欢存储源代码。发布分离的模块并将其另存为原始项目中的依赖项是否更有意义?它为node_modules目录的易变性提供了明确的解决方案,并且仅依赖npm,而不依赖git,符号链接或$ NODE_PATH解决方案。
凯文·科希尔

1
NODE_PATH看起来很不错。“只有在正确设置环境后,您的应用程序才能运行”,这始终是事实!获取环境设置(通常在一个文件中)是否比更改每个文件中的每个导入更容易?
CpILL

73

我喜欢node_modules为共享代码创建一个新文件夹,然后让node并要求执行其最佳功能。

例如:

- node_modules // => these are loaded from your package.json
- app
  - node_modules // => add node-style modules
    - helper.js
  - models
    - user
    - car
- package.json
- .gitignore

例如,如果你是car/index.js,你可以require('helper')和节点会发现它!

node_modules如何工作

节点有一个聪明的算法来解析模块,这在竞争对手的平台中是独一无二的。

如果require('./foo.js')/beep/boop/bar.js节点将寻找./foo.js/beep/boop/foo.js。以./或开头的路径../始终位于所调用文件的本地require()

但是,如果您需要一个非相对名称,例如require('xyz')from /beep/boop/foo.js,则节点按顺序搜索这些路径,在第一个匹配项处停止并在找不到任何内容的情况下引发错误:

/beep/boop/node_modules/xyz
/beep/node_modules/xyz
/node_modules/xyz

对于xyz存在的每个目录,节点将首先查找一个xyz/package.json以查看是否"main"存在字段。该"main"字段定义了如果您要负责哪个文件require()使用目录路径,。

例如,if /beep/node_modules/xyz是第一个匹配项,并且/beep/node_modules/xyz/package.json具有:

{
  "name": "xyz",
  "version": "1.2.3",
  "main": "lib/abc.js"
}

然后的出口/beep/node_modules/xyz/lib/abc.js将被退回 require('xyz')

如果没有package.json或没有"main"字段,index.js则假定:

/beep/node_modules/xyz/index.js

2
加载模块时如何工作的绝佳解释
goenning 2015年

2
这是一个非常优雅的解决方案,避免了以上答案中的所有问题。应该考虑答案,恕我直言。
rodurico '19

38

大图景

看来“确实很糟糕”,但要花点时间。实际上,这确实很好。显式require()s提供了完全的透明度,并且易于理解,就像在项目生命周期中呼吸新鲜空气一样。

这样想:您正在阅读一个示例,将您的脚趾浸入Node.js中,并且已经确定这是“非常糟糕的IMO”。您是Node.js社区的第二手负责人,他们在编写和维护Node.js应用程序上花费的时间比任何人都多。作者犯了这样的菜鸟错误?(而且我同意,从我的Ruby和Python背景来看,乍一看似乎是一场灾难。)

Node.js周围有很多宣传和反宣传。但是当尘埃落定时,我们将承认显式模块和“本地优先”软件包是采用的主要驱动力。

常见情况

当然,node_modules从当前目录中搜索父,祖父母,曾祖父母等。因此,您已安装的软件包已经可以这种方式工作。通常,您可以require("express")在项目中的任何位置使用它,而且效果很好。

如果您发现自己是从项目的根目录加载常用文件的(也许是因为它们是常用的实用程序功能),那么这是一个制作程序包的主要线索。打包非常简单:将文件移入node_modules/并放置在package.json 那里。瞧!该命名空间中的所有内容都可以从整个项目中访问。包是将代码放入全局名称空间的正确方法。

其他解决方法

我个人不使用这些技术,但是它们确实回答了您的问题,当然您比我更了解自己的情况。

您可以设置$NODE_PATH为项目根目录。当您搜索该目录时require()

接下来,您可能会折衷并且需要所有示例中的公共本地文件。该通用文件只是将真实文件重新导出到祖父母目录中。

示例/下载/app.js(以及许多其他喜欢的示例

var express = require('./express')

示例/下载/express.js

module.exports = require('../../')

现在,当您重新放置这些文件时,最坏的情况是修复了一个填充模块。


14
我同意Node.js家伙一定选择了相对需求是有原因的。我只是看不到它的优势,也无法从您的回答中看出。对我来说仍然感觉“不好”;)
Adam Schmideg

21
“您是Node.js社区的第二手负责人”-这些负责人决定使用回调而不是期货/承诺。我的大部分nodejs咨询都涉及诅咒所说的“领导者”,并说服人们使用JVM。在使用nodejs几个月后,这要容易得多:)
David Sergey

8
@nirth,转到JVM吗?看在上帝的份上,为什么呢?
伊万乔2014年

31
“您是Node.js社区的第二个猜测领袖”,请避免这种令人思想震撼的语气。
atlex2 2015年

15
该死的,他是第二个猜测节点负责人。这就是行业发展的方式。如果节点人员没有第二次猜测支持基于线程的并发模型的领导者,那么我们将没有节点。
d512

20

看一下node-rfr

就这么简单:

var rfr = require('rfr');
var myModule = rfr('projectSubDir/myModule');

我认为第二行应该是var myModule = rfr('/ projectSubDir / myModule');
西科斯基2014年

1
从文档中:var module2 = rfr('lib / module2'); //可以省略前导斜杠。
igelineau

我尝试了一下,它的rfr可以与节点一起执行,但是可以用VS Code中断代码导航。。。我找不到解决方法,无法在VS中使用自动完成功能...
Alex Mantaut

13

如果您使用yarn而不是npm,则可以使用工作区

假设我有一个services我希望更轻松地需要的文件夹:

.
├── app.js
├── node_modules
├── test
├── services
   ├── foo
   └── bar
└── package.json

要创建Yarn工作区,请在以下位置创建一个package.json文件services folder

{
  "name": "myservices",
  "version": "1.0.0"
}

在您的主要package.json中添加:

"private": true,
"workspaces": ["myservices"]

yarn install从项目的根目录运行。

然后,您可以在代码中的任何地方执行以下操作:

const { myFunc } = require('myservices/foo')

而不是这样的:

const { myFunc } = require('../../../../../../services/foo')

6
可能是要澄清这仅适用于yarn,不适用于npm 的想法?我认为它可能也适用于npm,因此花了一些时间想知道自己做错了什么,直到尝试使用yarn为止。可能是一个愚蠢的假设,但也许我并不是唯一的一个。
ArneHugo '19

2
我进行了一些编辑以弄清楚。对困惑感到抱歉。
cyberwombat

12

恕我直言,最简单的方法是将自己的功能定义为GLOBAL对象的一部分。projRequire.js在项目的根目录中创建,内容如下:

var projectDir = __dirname;

module.exports = GLOBAL.projRequire = function(module) {
  return require(projectDir + module);
}

在使用require任何特定于项目的模块之前,在您的主文件中:

// init projRequire
require('./projRequire');

之后,以下对我有用:

// main file
projRequire('/lib/lol');

// index.js at projectDir/lib/lol/index.js
console.log('Ok');


@Totty,我想出了另一个解决方案,该解决方案适用于您在评论中描述的情况。说明将会出现tl;dr,因此我最好用测试项目的结构来显示图片。


好吧,到目前为止,这似乎是最好的方法。我这样做:GLOBAL.requires = require('r')。r; 在我的index.js文件中。但是我的誓言测试中存在问题,它们没有运行index.js,所以我的测试失败了,因为requireS是未定义的。无论如何,现在我可以添加GLOBAL.requires = require('r')。r; 在每个测试的顶部。有更好的主意吗?github.com/totty90/production01_server/commit/…– Totty.js 2012
6


当我在“ pathes-test / node_modules / other.js”中并且需要“ pathes-test / node_modules / some.js”时,会发生问题。我应该用require('./ some')代替require(“ prj / some”)。这样,我所有的应用程序都将位于node_modules目录中?
Totty.js 2012年

@Totty,prj/someprj/other(经过测试require('prj/some')不需要。您所有应用程序的通用模块都可以到达那里(例如数据库层)。可以说,您的位置不会有任何变化lib。尝试看看是否适合。
Aleksei Zabrodskii 2012年

是的,我已经对其进行了更新:github.com/totty90/production01_server/tree/master/node_modules / ...效果很好。但是我可以不使用node_modules将所有文件都放在一个级别上吗?
Totty.js 2012年

12

process.cwd()在我的项目中使用。例如:

var Foo = require(process.cwd() + '/common/foo.js');

可能值得注意的是,这将导致require一条绝对的道路,尽管我尚未遇到与此相关的问题。


1
这是个坏主意,因为CWD不必与应用程序保存在同一目录中。
jiwopene

11

有这个问题的一个很好的讨论在这里

我遇到了一个相同的体系结构问题:想要一种为我的应用程序提供更多组织和内部名称空间的方法,而无需:

  • 将应用程序模块与外部依赖项混合在一起,或者为专用于应用程序的代码而困扰于私有npm仓库
  • 使用相对需求,这使得重构和理解更加困难
  • 使用符号链接或更改节点路径,这可能会使源位置模糊不清,并且不能很好地与源代码控制一起使用

最后,我决定使用文件命名约定而不是目录来组织代码。结构如下所示:

  • npm-shrinkwrap.json
  • package.json
  • node_modules
    • ...
  • src
    • app.js
    • app.config.js
    • app.models.bar.js
    • app.models.foo.js
    • app.web.js
    • app.web.routes.js
    • ...

然后在代码中:

var app_config = require('./app.config');
var app_models_foo = require('./app.models.foo');

要不就

var config = require('./app.config');
var foo = require('./app.models.foo');

和外部依赖关系通常可以从node_modules获得:

var express = require('express');

这样,所有应用程序代码都按层次结构组织到模块中,并且可用于所有相对于应用程序根目录的其他代码。

当然,主要的缺点是在文件浏览器中,您无法像实际上将树组织成目录一样来展开/折叠树。但是我喜欢它非常清楚所有代码的来源,并且它不使用任何“魔术”。


从您链接的要点来看,解决方案7“包装器”非常简单方便。
2014年

我看到了更多的便利-将文件“移动”到另一个“文件夹”成为重命名-这比移动文件更容易。另外,我倾向于注意到,在项目工作了半小时之后,几乎所有应用树都得到了扩展。添加1级文件夹空间可以使大型代码库易于管理,并且不会引入太多../x/x已经可读的代码。
滑雪

您正在重新设计文件夹,使用点而不是斜杠来克服nodejs的明显不足。
Simone Gianni

9

假设您的项目根目录是当前工作目录,则该目录应该可以正常工作:

// require built-in path module
path = require('path');

// require file relative to current working directory
config = require( path.resolve('.','config.js') );

config = require('./config.js');也有效。
cespon

7
@cespon否,仅与所需文件有关。
protometa

8

我已经尝试了许多这样的解决方案。我最终将其添加到主文件(例如index.js)的顶部:

process.env.NODE_PATH = __dirname;
require('module').Module._initPaths();

加载脚本后,这会将项目根目录添加到NODE_PATH。允许我通过引用来自项目根目录的相对路径(例如)来要求项目中的任何文件var User = require('models/user')。只要您在项目根目录中运行主脚本,然后再在项目中运行其他任何东西,此解决方案就应该起作用。


8

有些答案是说,最好的方法是将代码作为一个软件包添加到node_module,这可能是丢失../../../in require 的最好方法,但是它们都没有给出这样做的方法。

从版本开始,2.0.0您可以从本地文件安装软件包,这意味着您可以在根目录中创建包含所有所需软件包的文件夹,

-modules
 --foo
 --bar 
-app.js
-package.json

因此,在package.json中,您可以将modules(或foobar)添加为包,而无需发布或使用外部服务器,如下所示:

{
  "name": "baz",
  "dependencies": {
    "bar": "file: ./modules/bar",
    "foo": "file: ./modules/foo"
  }
}

之后,您可以执行npm install,然后可以使用访问代码var foo = require("foo"),就像处理所有其他软件包一样。

更多信息可以在这里找到:

https://docs.npmjs.com/files/package.json#local-paths

这里是如何创建一个包:

https://docs.npmjs.com/getting-started/creating-node-modules


1
“此功能对于本地脱机开发和创建需要npm安装的测试很有用,您不想在不打外部服务器的地方安装npm,但是在将程序包发布到公共注册表时不应使用。”
瑞安·史密斯

7

您可以使用我制作的模块Undot。它没有什么高级的,只是一个帮助程序,因此您可以简单地避免那些麻烦。

例:

var undot = require('undot');
var User = undot('models/user');
var config = undot('config');
var test = undot('test/api/user/auth');

6

您可以在app.js中定义以下内容:

requireFromRoot = (function(root) {
    return function(resource) {
        return require(root+"/"+resource);
    }
})(__dirname);

然后无论何时何地,无论您身在何处,都希望从根源获得某些东西,只需使用requireFromRoot而不是原始的require即可。到目前为止对我来说还算不错。


谢谢!我认为这非常聪明和直接。
瑞安

父亲,请原谅我,因为我犯了罪。我将此移植到ES6并获得了以下信息:requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);。喜欢解决方案,但是您真的必须像这样绑定__dirname吗?
Nuck

1
我的记忆对此有些朦胧,但是我相信__dirname会根据其中使用的文件来更改值。现在可能是因为该函数是在单个位置定义的,但在多个位置使用,因此即使没有此绑定,该值也将保持不变,但我只是这样做以确保确实如此。
user1417684 2014年

很久以前这样做,导致测试环境等问题。不值得的开销。随机的新全球使新人们不确定bla bla
Dembinski

您如何使用require此功能?
Darko Maksimovic

5

这是我六个月以上的实际工作方式。我在项目中使用名为node_modules的文件夹作为我的根文件夹,通过这种方式,它将始终在我称之为绝对需求的任何地方查找该文件夹:

  • node_modules
    • 我的项目
      • index.js我可以用require(“ myProject / someFolder / hey.js”)代替require(“ ./ someFolder / hey.js”)
      • 包含hey.js的someFolder

当您嵌套在文件夹中时,此功能将更为有用;如果以绝对方式进行设置,则更改文件位置的工作将大大减少。我只在整个应用程序中使用2个相对要求。


4
我用类似的方法,不同的是我添加本地(项目)node_modules/src,并留下/node_modules了厂商让事情分开。所以我有/src/node_modules本地代码和/node_modules供应商。
MariusBalčytis13年

33
恕我直言,node_modules文件夹仅用于node_modules。将整个项目放在该文件夹中不是一个好习惯。
McSas

2
@McSas您会建议如何获得与上述相同的效果?
spieglio 2014年

3
@cspiegl您可以使用NODE_PATH环境变量
Christopher Tarquini

5

恕我直言,实现此目的最简单的方法是在应用启动时创建一个指向的符号链接node_modules/app(或您所说的任何名称),该链接指向../app。然后,您可以致电require("app/my/module")。在所有主要平台上都可以使用符号链接。

但是,您仍然应该将内容拆分为较小的,可维护的模块,这些模块通过npm安装。您也可以通过git-url安装私有模块,因此没有理由拥有一个单一的应用程序目录。


Windows上的支持需要对Node和OS有更深入的了解。它可能会限制开源项目的广泛使用。
Steven Vachon 2014年

通常,我不会将这种模式用于库(大多数开源项目都在其中)。但是,可以在npm build挂钩中创建这些符号链接,因此用户不需要深入的知识。
约翰内斯·埃瓦尔德

可以,但是Windows上的Node.js默认情况下不支持符号链接。
史蒂文·瓦雄

4

在您自己的项目中,您可以修改根目录中使用的任何.js文件,并将其路径添加到process.env变量的属性中。例如:

// in index.js
process.env.root = __dirname;

之后,您可以在任何地方访问该属性:

// in app.js
express = require(process.env.root);

4

另一个答案:

想象一下这个文件夹结构:

  • node_modules
    • Lodash
  • src
    • 子目录
      • foo.js
      • bar.js
    • main.js
  • 测试

    • test.js

然后在test.js中,您需要这样的文件:

const foo = require("../src/subdir/foo");
const bar = require("../src/subdir/bar");
const main = require("../src/main");
const _ = require("lodash");

并在main.js中

const foo = require("./subdir/foo");
const bar = require("./subdir/bar");
const _ = require("lodash");

现在,您可以将babelbabel-plugin-module-resolver与this一起使用。babelrc文件配置2个根文件夹:

{
    "plugins": [
        ["module-resolver", {
            "root": ["./src", "./src/subdir"]
        }]
    ]
}

现在,您可以在测试src中以相同的方式要求文件:

const foo = require("foo");
const bar = require("bar");
const main = require("main");
const _ = require("lodash");

并且如果要使用es6模块语法:

{
    "plugins": [
        ["module-resolver", {
            "root": ["./src", "./src/subdir"]
        }],
        "transform-es2015-modules-commonjs"
    ]
}

然后您可以像这样在测试src中导入文件:

import foo from "foo"
import bar from "bar"
import _ from "lodash"


3

examples目录中不能包含node_modules带有指向项目根目录的符号链接的,project -> ../../因此允许示例使用require('project'),尽管这不会删除映射,但允许源使用require('project')而不是require('../../')

我已经对此进行了测试,并且可以在v0.6.18中使用。

目录清单project

$ ls -lR project
project:
drwxr-xr-x 3 user user 4096 2012-06-02 03:51 examples
-rw-r--r-- 1 user user   49 2012-06-02 03:51 index.js

project/examples:
drwxr-xr-x 2 user user 4096 2012-06-02 03:50 node_modules
-rw-r--r-- 1 user user   20 2012-06-02 03:51 test.js

project/examples/node_modules:
lrwxrwxrwx 1 user user 6 2012-06-02 03:50 project -> ../../

的内容为对象index.js的属性分配一个值,exportsconsole.log使用一条消息指出该消息是必需的。的内容test.jsrequire('project')


您可以显示测试的源代码吗?很好,如果我必须以这种方式要求('project.a')会起作用吗?
Totty.js 2012年

你是什么意思require('project.a')?我认为这可能意味着require('project/a'),虽然require('project').a也可能?
Dan D.

但是在您的示例中,我需要在每个文件夹中都有一个需要require方法的模块中创建这些文件夹。无论如何,您将需要注意“ ../”的时间,具体取决于文件夹。
Totty.js 2012年

实际上,链接只需要node_modules位于两个文件的最接近的父目录中,然后两个链接就相同。参见nodejs.org/api/…–
Dan D.

并且从那个位置是相对的。例如:project/node_modules/project -> ../
Dan D.

2

如果有人正在寻找另一种方法来解决此问题,这是我对这项工作的贡献:

https://www.npmjs.com/package/use-import

基本思想是:在项目的根目录中创建一个JSON文件,该文件将文件路径映射到速记名称(或使用use-automapper来为您完成此操作)。然后,您可以使用这些名称请求文件/模块。像这样:

var use = require('use-import');
var MyClass = use('MyClass');

就是这样。


2

我想做的是为此利用节点如何从node_module目录中加载。

如果尝试加载模块“事物”,则可能会执行类似的操作

require('thing');

然后,节点将在“ node_module”目录中查找“ thing”目录。

由于node_module通常位于项目的根目录,因此我们可以利用这种一致性。(如果node_module不在根本上,那么您还需要处理其他一些自感头痛。)

如果进入目录然后再​​退出目录,则可以获得到节点项目根目录的一致路径。

require('thing/../../');

然后,如果我们要访问/ happy目录,则可以执行此操作。

require('thing/../../happy');

尽管这有点棘手,但是我觉得如果node_modules加载功能的功能发生变化,将会遇到更大的问题。此行为应保持一致。

为了清楚起见,我这样做是因为模块的名称无关紧要。

require('root/../../happy');

我最近将其用于angular2。我想从根目录加载服务。

import {MyService} from 'root/../../app/services/http/my.service';

关于Angular参考,使用标准CLI应用程序,您可以简单地import src/app/my.service,也可以将VSC配置为对打字稿文件使用非相对导入。
软盘

2

我写了这个小程序包,使您可以按从项目根目录开始的相对路径来请求程序包,而无需引入任何全局变量或覆盖节点默认值

https://github.com/Gaafar/pkg-require

它像这样工作

// create an instance that will find the nearest parent dir containing package.json from your __dirname
const pkgRequire = require('pkg-require')(__dirname);

// require a file relative to the your package.json directory 
const foo = pkgRequire('foo/foo')

// get the absolute path for a file
const absolutePathToFoo = pkgRequire.resolve('foo/foo')

// get the absolute path to your root directory
const packageRootPath = pkgRequire.root()

有时我在主项目中有私有软件包,此脚本将与此分开。除此之外,我不确定是否可以与webpack一起使用(如果您像我一样将webpack与node.js一起使用)
Totty.js,

如果您嵌套了包含软件包文件的目录,则每个目录将只能在其软件包中需要文件。那不是你想要的行为吗?我尚未使用webpack进行测试。
加菲

这对于一个简单的项目而言非常理想,并且比其他任何答案都容易得多。
byxor

2

只是想跟进伟大的答案保罗·莫雷蒂和Browserify。如果您使用的是Transpiler(例如babel,打字稿),并且有单独的文件夹来存放源代码和已编译的代码(例如src/和)dist/,则可以使用多种解决方案,例如

node_modules

具有以下目录结构:

app
  node_modules
    ... // normal npm dependencies for app
  src
    node_modules
      app
        ... // source code
  dist
    node_modules
      app
        ... // transpiled code

然后,您可以让babel等将src目录转换为dist目录。

符号链接

使用symlink,我们可以消除一些嵌套层次:

app
  node_modules
    ... // normal npm dependencies for app
  src
    node_modules
      app // symlinks to '..'
    ... // source code
  dist
    node_modules
      app // symlinks to '..'
    ... // transpiled code

babel --copy-files警告--copy-files标志babel不能很好地处理符号链接。它可能会继续导航到..符号链接中,并回味无穷。解决方法是使用以下目录结构:

app
  node_modules
    app // symlink to '../src'
    ... // normal npm dependencies for app
  src
    ... // source code
  dist
    node_modules
      app // symlinks to '..'
    ... // transpiled code

这样,under下的代码src仍将app解析为src,而babel将不再看到符号链接。


谢谢,但是,我不建议您这样做。首先,您将丢失所有导入,它们不会由您的IDE计算。如果您使用其他工具(例如流类型),则也将无法正常工作。
Totty.js

在我看来,实际上流程似乎可行,这并不奇怪,因为解决方案取决于标准的节点模块分辨率模型和符号链接。因此,了解流程之类的工具并不是真正的魔术。但是IDE是不同的。
user716468

2

我一直在寻找完全相同的简单性来要求任何级别的文件,并且发现了module-alias

只需安装:

npm i --save module-alias

打开您的package.json文件,您可以在此处为路径添加别名,例如

"_moduleAliases": {
 "@root"      : ".", // Application's root
 "@deep"      : "src/some/very/deep/directory/or/file",
 "@my_module" : "lib/some-file.js",
 "something"  : "src/foo", // Or without @. Actually, it could be any string
}

并简单地使用别名:

require('module-alias/register')
const deep = require('@deep')
const module = require('something')


1

我们将尝试一种新方法来解决此问题。

以其他已知项目(例如spring和guice)为例,我们将定义一个“ context”对象,其中将包含所有“ require”语句。

然后,该对象将传递给所有其他模块使用。

例如

var context = {}

context.module1 = require("./module1")( { "context" : context } )
context.module2 = require("./module2")( { "context" : context } )

这就要求我们将每个模块编写为一个接收opt的函数,无论如何,这对我们来说都是一种最佳实践。

module.exports = function(context){ ... }

然后您将引用上下文,而不需要任何内容​​。

var module1Ref = context.moduel1;

如果愿意,您可以轻松编写一个循环来执行require语句

var context = {};
var beans = {"module1" : "./module1","module2" : "./module2" }; 
for ( var i in beans ){
    if ( beans.hasOwnProperty(i)){
         context[i] = require(beans[i])(context);
    }
};

当您要模拟(测试)时,这应该使工作变得更轻松,并且在使代码作为包可重用的同时解决了您的问题。

您还可以通过将bean声明与上下文初始化代码分开来重用上下文初始化代码。例如,您的main.js文件可能看起来像这样

var beans = { ... }; // like before
var context = require("context")(beans); // this example assumes context is a node_module since it is reused.. 

此方法也适用于外部库,不需要在每次需要它们时都对其名称进行硬编码-但是,由于它们的导出不是期望上下文的函数,因此将需要特殊对待。

稍后,我们还可以将bean定义为函数-允许我们require根据环境使用不同的模块-但它超出了该线程的范围。


1

我在遇到同一问题时遇到了麻烦,所以我写了一个名为include的软件包。

Include句柄通过查找package.json文件来确定项目的根文件夹,然后将您赋予它的path参数传递给本机require(),而不会造成所有相对路径混乱。我想这不是对require()的替代,而是一种用于处理非打包/非第三方文件或库的工具。就像是

var async = require('async'),
    foo   = include('lib/path/to/foo')

我希望这会有所帮助。


1

如果应用程序的入口点js文件(即您实际在其上运行“节点”的文件)位于项目的根目录中,则可以使用rootpath npm模块轻松地做到这一点。只需通过安装

npm install --save rootpath

...然后在入口点js文件的最顶部添加:

require('rootpath')();

从那时起,所有require调用现在都相对于项目根目录-例如,require('../../../config/debugging/log'); 变为require('config/debugging/log');(其中config文件夹位于项目根目录中)。


1

简单来说,您可以将自己的文件夹称为module:

为此,我们需要:全局和app-module-path模块

这里的“ App-module-path”是模块,它使您可以向Node.js模块搜索路径添加其他目录。而“ global”是,附加到该对象的任何内容都可以在应用程序中的任何位置使用。

现在看一下这个片段:

global.appBasePath = __dirname;

require('app-module-path').addPath(appBasePath);

__dirname是节点的当前运行目录。您可以在此处提供自己的路径以搜索模块的路径。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.