10

Is it possible to get the file name of the current JavaScript module?

// item.mjs
function printName() {
  console.log(...);  // >> item or item.mjs
};

If not, why not? Sandboxing, etc.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
isar
  • 1,661
  • 1
  • 20
  • 39
  • 1
    In Node.js it's just `__filename__`. If you're looking for a client-side solution, see [this answer](https://stackoverflow.com/a/22745553/1541563). – Patrick Roberts Aug 26 '19 at 19:25
  • @PatrickRoberts Thanks but I'm not talking about Node.js files. – isar Aug 26 '19 at 19:28
  • Are you talking about files loaded with script tags or you are using some js framework, where you need file name? – Mahendra Pratap Aug 26 '19 at 19:31
  • @MahendraPratap I'm talking about JavaScript modules imported with a script tag (i.e. ``). – isar Aug 26 '19 at 19:40
  • You can get scripts by document.getElementsByTagName('script') and then check there src for getting name, but getting current module name would not be possible i think. – Mahendra Pratap Aug 26 '19 at 19:44
  • Do you have the ability to modify the modules or are they out of your control? – daddygames Aug 26 '19 at 19:54
  • @daddygames I can modify the modules. – isar Aug 26 '19 at 19:57
  • 1
    @isar Clientside ES6 modules with no transpilation step? Then surely you're also brave enough to use [this experimental feature](https://github.com/tc39/proposal-import-meta) :-) – Bergi Aug 27 '19 at 00:39

3 Answers3

15

You are looking for the (proposed) import.meta meta property. What exactly this object holds depends on the environment, but in a browser you can use

// item.mjs
function printName() {
  console.log(import.meta.url);  // https://domain.example/js/item.mjs
}

You can extract the file name by parsing that with the URL interface, e.g.

console.log(new URL(import.meta.url).pathname.split("/").pop())
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
2
import { basename, dirname } from "node:path";
import { fileURLToPath } from "node:url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const filename = basename(__filename);

Alternatively, use zx script runner that sets __filename, __dirname.

Konstantin Tarkus
  • 37,618
  • 14
  • 135
  • 121
0

One potential solution: Each method in the mjs file may set a global variable that will be the name of the module. The printName() method would then print the current value of that global variable. That way, while processing, you can inspect the current state of that global variable for the name of the file currently executing.

global js

var global_mjs_name = 'none';

function printName() {
   console.log('processed in ' + global_mjs_name);
}

window.addEventListener('DOMContentLoaded', function(event){
    printName(); // output -> 'none'
    doWork({}); 
    printName(); // output -> 'item.mjs'
    doFunStuff();
    printName(); // output -> 'FunStuff.mjs'
});

inside item.mjs:

const item_js_name = 'item.mjs';

function doWork(data) {
   global_mjs_name = item_js_name; // every time you execute code within the module, update the global variable
   return processData(data);
}

inside some other module called FunStuff.mjs

const funstuff_js_name = 'FunStuff.mjs';

function doFunStuff() {
   global_js_name = funstuff_js_name; // update the global variable for the module
   return haveFun();
}

I'm not saying this is the best way to accomplish this task. Manually handling the changing of the global variable may be a pain.

daddygames
  • 1,880
  • 1
  • 11
  • 18