Sherif eldeeb
Sherif eldeeb

Reputation: 2186

using ESM imports in functions

when you add imports to an ESM package, you can resolve alias paths into the corresponding real ones, like this:

package.json

{
  "type": "module",
  "imports": { "#*": "./*" }
  ...
}

now we can use it like this import something from "#module" which resolves into import something from "./module"

but, I can't see any docs about using the same resolving mechanism for builtin functions (or maybe user functions either) that accept PathLike arguments like readFileSync

readFileSync("#file.txt")

I know it is a module resolving, but we can use it as a path resolving.

my question is: how to achieve the same mechanism to resolve any PathLike path, without a manual modification, because simply we need to dispense the relative paths

an example of manual resolving

function example(path: PathLike){
  let imports = /* read the property imports from package.json */
  let keys = Object.keys(imports)

  // make a loop, and for each key make something like this (needs additional work)
  let resolvedPath = path.replace('#','./')

  // now, use resolvedPath instead of path
}

example of nodejs resolving

function example2(path: PathLike){
  let resolvedPath = resolve(path)
}

in addition to the original work of resolve() it also uses the property import to resolve the path to avoid using relative paths

I ask if there is a way to achieve this goal.

The solution

thanks to @RickN this is the final solution:

export function resolveImports(path: PathLike): Promise<string> {
  return import.meta!.resolve!(path.toString()).then((resolvedPath) =>
    fileURLToPath(resolvedPath)
  );
}

Upvotes: 0

Views: 331

Answers (1)

RickN
RickN

Reputation: 13500

As of writing, you need a CLI flag to enable the resolve method in import.meta:

node --experimental-import-meta-resolve your-file.js

(The first part of the name speaks for itself.)

Then, in a script:

console.log( await import.meta.resolve('#foo/bar.js') );
// It can resolve any type of file, even if you can't import() it.
console.log( await import.meta.resolve('#foo/hello.txt') );

As it's a promise-based function, you'll need to await the result.

async function example2(path: PathLike){
  return import.meta.resolve(path);
}

As a side-note: this returns a URL (file:///...) so run the result through the built-in URL class url.fileURLToPath() if you just want a file path:

import { fileURLToPath } from 'node:url';
// OR: const { fileURLToPath } = require('node:url');
// For older node versions use `require('url')`

console.log( fileURLToPath(await import.meta.resolve('#foo/hello.txt')) );
// => /tmp/example/directory-with-modules-in-it/hello.txt

Upvotes: 1

Related Questions