在Node.JS中引用相对于应用程序根目录的文件的正确方法

use*_*940 21 linux node.js

我在AWS EC2上的Linux上运行了一个Node.JS应用程序,该应用程序使用fs模块读取HTML模板文件.以下是该应用程序的当前结构:

/server.js
/templates/my-template.html
/services/template-reading-service.js
Run Code Online (Sandbox Code Playgroud)

HTML模板将始终位于该位置,但是,模板读取服务可能会移动到不同的位置(更深的子目录等).在模板读取服务中,我使用fs.readFileSync()来加载文件,像这样:

var templateContent = fs.readFileSync('./templates/my-template.html', 'utf8');
Run Code Online (Sandbox Code Playgroud)

这会引发以下错误:

Error: ENOENT, no such file or directory './templates/my-template.html'
Run Code Online (Sandbox Code Playgroud)

我假设这是因为路径'./'正在解析到'/ services /'目录而不是应用程序根目录.我也尝试将路径更改为'../templates/my-template.html'并且有效,但它看起来很脆弱,因为我认为这只是相对于"向上一个目录"进行解析.如果我将模板读取服务移动到更深的子目录,那么该路径将会中断.

那么,相对于应用程序根目录引用文件的正确方法是什么?

gre*_*zap 29

要获取运行节点进程的目录的绝对文件系统路径,可以使用process.cwd().因此,假设你正在运行/server.js作为实现的过程/services/template-reading-service.js作为一个模块,那么你可以做从以下/service/template-reading-service.js:

var appRoot = process.cwd(),
    templateContent = fs.readFileSync(appRoot + '/templates/my-template.html', 'utf8');
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,那么您可能将/service/template-reading-service.js作为一个单独的进程运行,在这种情况下,您将需要进行任何启动,该进程将其作为主要应用程序处理的路径传递给它根.例如,如果/server.js将/service/template-reading-service.js作为一个单独的进程启动,那么/server.js应该将它自己的process.cwd()传递给它.

  • 对于任何未来的人来看这些答案:process.cwd不一定是你要找的答案.例如,在Windows上,如果从.bat文件运行节点进程,process.cwd()将返回.bat文件的路径,而不是节点项目的根目录.我相信类似的规则适用于Linux和Mac. (2认同)

Ins*_*dJW 26

尝试

var templateContent = fs.readFileSync(path.join(__dirname, '../templates') + '/my-template.html', 'utf8');
Run Code Online (Sandbox Code Playgroud)

  • __dirname实际上不是当前脚本/模块所在的路径吗?所以在我的例子中,当从'template-reading-service.js'执行时,不会__dirname解析为'/ services /'? (3认同)

小智 18

接受的答案是错误的.硬编码path.join(__dirname, '../templates')将完全执行不需要的操作,service-XXX.js如果文件移动到子位置(如给定示例services/template),则使文件中断主应用程序.

使用process.cwd()将返回启动正在运行的进程的文件的根路径(因此,例如/Myuser/myproject/server.js返回/Myuser/myproject/).

这是问题的副本从运行的node.js应用程序确定项目根目录.

在那个问题上,__dirname答案得到了应有的正确鞭打.提防绿色标记,路人.

  • 对于任何未来的人来看这些答案:process.cwd不一定是你要找的答案.例如,在Windows上,如果从.bat文件运行节点进程,process.cwd()将返回.bat文件的路径,而不是节点项目的根目录.我相信类似的规则适用于Linux和Mac. (3认同)
  • 我使用app-root-path包时遇到了可怕的时间.有两种方法可以启动我的应用程序,节点lib/my_app.js或bin/my_app.js.`path.join(__ dirname)`我花了很多时间和代码修补app-root-path来跨平台工作,最后我切换到`path.join(__ dirname)`只要项目文件没有转过来. (2认同)

Dav*_*ave 6

对于 ES 模块,__dirname不可用,因此请阅读此答案并使用:

import { resolve, dirname, join } from 'path'
import { fileURLToPath } from 'url'
import fs from 'fs'

const relativePath = a => join(dirname(fileURLToPath(import.meta.url)), a)

const content1 = fs.readFileSync(relativePath('./file.xyz'), 'utf8') // same dir
const content2 = fs.readFileSync(relativePath('../file.xyz'), 'utf8') // parent dir
Run Code Online (Sandbox Code Playgroud)