50

I have a Node.JS application running on Linux at AWS EC2 that uses the fs module to read in HTML template files. Here is the current structure of the application:

/server.js
/templates/my-template.html
/services/template-reading-service.js

The HTML templates will always be in that location, however, the template-reading-service may move around to different locations (deeper subdirectories, etc.) From within the template-reading-service I use fs.readFileSync() to load the file, like so:

var templateContent = fs.readFileSync('./templates/my-template.html', 'utf8');

This throws the following error:

Error: ENOENT, no such file or directory './templates/my-template.html'

I'm assuming that is because the path './' is resolving to the '/services/' directory and not the application root. I've also tried changing the path to '../templates/my-template.html' and that worked, but it seems brittle because I imagine that is just resolving relative to 'up one directory'. If I move the template-reading-service to a deeper subdirectory, that path will break.

So, what is the proper way to reference files relative to the root of the application?

5 Answers 5

41

Try

var templateContent = fs.readFileSync(path.join(__dirname, '../templates') + '/my-template.html', 'utf8');
Sign up to request clarification or add additional context in comments.

7 Comments

Isn't __dirname actually the path to where the current script/module is? So in my example, when executing from within 'template-reading-service.js' wouldn't __dirname resolve to '/services/'?
@user1438940 I thought you executes the file reading code in /server.js. Try "../templates/my-template.html"
no, the code executing the fs.getFileSync is in the "template-reading-service.js". I don't want to use "../"; that's the entire point of my question. If I use "../" and then later I move "template-reading-service.js" from the "/services/" directory to "/services/templating/" then all my code breaks. Or, if I want to have the path to the template directory as a setting in a global config, which would then be used by 20 different other services, all located at different places in the directory structure, then "../" would not work from everywhere
@user1438940 process.cwd() returns the absolute path of "js" file executed. Therefore you can run a js file in the root directory of the project directory and attach the rest at the end.
@InspiredJW it looks like you edited out your __dirname advice, but I ended up using it as my solution. In a global config, I used the following, which still seems pretty crappy to me.... templates: { directoryPath: path.join(__dirname, '../templates/') }
|
35

To get an absolute filesystem path to the directory where the node process is running, you can use process.cwd(). So assuming you are running /server.js as a process which implements /services/template-reading-service.js as a module, then you can do the following from /service/template-reading-service.js:

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

If that doesn't work then you may be running /service/template-reading-service.js as a separate process, in which case you will need to have whatever launches that process pass it the path you want to treat as the primary application root. For example, if /server.js launches /service/template-reading-service.js as a separate process then /server.js should pass it its own process.cwd().

3 Comments

So, I thought this might work for me, but it doesn't work in all of my environments. In my production environment, I'm using forever so process.cwd returns /.
For any future people looking at these answers: process.cwd is not necessarily the answer you're looking for. On windows, for example, if you run a node process from a .bat file, process.cwd() returns the path to the .bat file, not to the root of your node project. I believe similar rules apply to Linux and Mac.
process.cwd() returns the path of the directory where the entry script was called from, not the directory where the files is located. So, if you call index.js from /var/www/project, process.cwd() will be '/var/www/project', but if you call the same script from /var/www it will be /var/www.
21

Accepted answer is wrong. Hardcoding path.join(__dirname, '../templates') will do exactly what is not wanted, making the service-XXX.js file break the main app if it moves to a sub location (as the given example services/template).

Using process.cwd() will return the root path for the file that initiated the running process (so, as example a /Myuser/myproject/server.js returns /Myuser/myproject/).

This is a duplicate of question Determine project root from a running node.js application.

On that question, the __dirname answer got the proper whipping it deserves. Beware of the green mark, passers-by.

2 Comments

I had a horrible time using the app-root-path package. There were two ways to start my app, node lib/my_app.js or bin/my_app.js. path.join(__dirname) I spent lots of time and code patching app-root-path to work across platforms, ultimately I switched to path.join(__dirname) which will work as long as the project files don't shift around.
For any future people looking at these answers: process.cwd is not necessarily the answer you're looking for. On windows, for example, if you run a node process from a .bat file, process.cwd() returns the path to the .bat file, not to the root of your node project. I believe similar rules apply to Linux and Mac.
6

For ES modules, __dirname is not available, so read this answer and use:

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

Comments

0

We can use path madule to access the current path

const dirname = __dirname;
const path = require('path');


path.resolve(dirname, 'file.txt')

where

dirname  - is give us present working directory path name
file.txt - file name required to access

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.