Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

resolving a path in node when using .mjs files

I'm writing a quick/simple deploy script in node using the module format mjs so that I can use the module syntax.

One of the things I'm doing in the file is resolving an absolute path from a relative one based on the current modules' directory.

In the past I would have done something like:

const path = require("path") 

const distPath = path.resolve(__dirname, "..", "dist")

But in module js I lose the __dirname symbol and get the error:

ReferenceError: __dirname is not defined

So I hop online to see what the mjs version of this is (woof, searching for "resolve path in mjs" or any permutation on that is rough b/c everything points to the original way of doing it :P), and from what I learned I can do this:

import { dirname, resolve } from "path"
import { fileURLToPath } from "url"

const distPath = resolve(dirname(fileURLToPath(import.meta.url)), "..", "dist")

Which works, but is a handful to type.

If this is the correct way of doing it then I'll just memorize the new approach, but this feels like such a common task that there must be a better way of doing it in module js and I just haven't found it.

Any alternatives?

like image 690
Chris Schmitz Avatar asked May 02 '26 07:05

Chris Schmitz


1 Answers

I'm using these helpers which get the job done:

import Path from 'path'
import { fileURLToPath } from 'url'

/**
 * Get the directory of a file
 * 
 * @example dir(import.meta)
 *
 * @param   {{url: string}}   meta    An `import.meta` object
 * @return  {string}                  The absolute path to the import's folder
 */
export function dir (meta) {
  return Path.dirname(fileURLToPath(meta.url))
}

/**
 * Resolve path relative to process or imported file
 * 
 * @example resolve('path/to/file.txt')
 * @example resolve(import.meta, 'path/to/file.txt')
 * @example resolve(import.meta, 'folder', 'file.txt')
 *
 * @param   {string|{url:string}}   paths       Pass one or more parts to resolve from root.
 *                                              Pass `import.meta` as the first argument to resolve from that file
 * @return  {string}                            An absolute path
 */
export function resolve (...paths) {
  const [base, ...parts] = paths
  return base?.url
    ? Path.resolve(dir(base), ...parts)
    : Path.resolve(...paths)
}
like image 173
Dave Stewart Avatar answered May 04 '26 21:05

Dave Stewart