2

In node, in order to determine if I'm in the entry file, the file referenced directly by node, I can use __file__ === process.argv[1]. process.argv is an array containing the arguments I used to call the node script. Therefore, the first argv is usually node, the second is the file I'm using. This is useful if I'm creating a library and I want to know whether I'm calling the library directly, for example for testing. This would typically get minified out in a production build.

How can I do the same thing in a browser? Before ES6 modules, all JavaScript files were effectively global, meaning the <script> tags were all called directly by the HTML. However, now, with ES6 modules, it is possible to import another JavaScript file. How do I determine whether I am in a file directly sourced by the browser, with <script src="..."></script>, or whether I am in a file that was imported by another script?

This could be useful for react components, especially in libraries. If I am in the "entry" file, I can render myself in a tag that I choose, perhaps <main>. If not, I can assume I'm being imported by another component, which will presumably render itself or be rendered in some other way. The same concept applies to other component-based libraries, like angular 2+, aurelia, etc. For example,

import React from 'react';
import {render} from 'react-dom';

if(isEntryPoint()) {
    const main = document.querySelector('main');
    render(<App />, main);
}

function App() {
    return <div>Hello World!<div>;
}

So how do I find out if a file is directly referenced by the browser via <script src="..."></script>, or if it was imported by another JavaScript file? How should the isEntryPoint function look?

trysis
  • 8,086
  • 17
  • 51
  • 80
  • You cannot, and you should not. The established best practice is to provide two different modules, one "main" entry point and one library file. – Bergi Jul 04 '20 at 17:08
  • Possible duplicate of [Detect whether ES Module is run from command line in Node](https://stackoverflow.com/q/57838022/1048572) – Bergi Jul 04 '20 at 17:16
  • This is nowhere near a duplicate. The other question is node, this one is in-beowser. – trysis Jul 04 '20 at 18:39
  • Oops, I mean to link the more generic [`if __name__ == '__main__'` equivalent in javascript es6 modules](https://stackoverflow.com/q/34842738/1048572). – Bergi Jul 04 '20 at 18:41
  • Hmmm... Yes, this question is a closer dupe of that one. I still don't think it's an exact dupe, though, because that one isn't browser-specific, while this one is. – trysis Jul 04 '20 at 19:14

1 Answers1

4

I don't believe there's any reasonable way for a browser-hosted module to know that it's been loaded directly rather than by another module. The unreasonable way I can think to do it is to compare the last segment of the URL in import.meta.url with the script elements present in the DOM and seeing if one matches.

I don't recommend it.

In fact, even then, if for some reason I have

<script type="module" src="./myfile.js"></script>
<script type="module" src="./your-library.js"></script>

and myfile.js does:

import /* stuff */ from "./your-library.js";

That would make your library think it was loaded directly when it fact it was loaded via myfile.js.

So I really don't recommend it. ;-)

Instead, you're probably better off providing your library (your-library.js) with a setup call the code using it can use, and an optional additional module (auto-your-library.js or whatever) that A) loads your library, and B) does the setup call. (If you want to provide the automatic setup feature at all.)

Note: import.meta is new in ES2020.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Yes, I was thinking of doing this. I was afraid it might take too long to compare all the ` – trysis Jul 04 '20 at 18:38
  • @trysis if you really want such behaviour of the library, the best practice would be to use ` – Bergi Jul 04 '20 at 18:45
  • @trysis - Except for the `.mjs` part. :-) – T.J. Crowder Jul 05 '20 at 08:24
  • `.mjs` indicates a module, it doesn't tell you which module is the entry point. – trysis Jul 05 '20 at 14:56
  • @trysis - My point was that `.mjs` is not widely-regarded as best practice. What identifies it as a module is `type="module"`. Browsers don't care about file extensions. – T.J. Crowder Jul 05 '20 at 16:37
  • Would `import.parent` work, like in the answer to the question that @Bergi thought was a dupe? – trysis Jul 09 '20 at 23:36
  • @trysis - You mean `module.parent`? No, that's Node.js-specific. – T.J. Crowder Jul 10 '20 at 06:59