How do I detect if an ES Module is the main module? - javascript

How can I detect if an ECMAScript module is the main module? This is easy for CommonJS modules (see Detect if called through require or directly by command line).
There is no require or require.main
No process.mainModule
The import.meta has no clues, only has url

You could use es-main.
From the package README:
import esMain from 'es-main';
if (esMain(import.meta)) {
// Module run directly.
}
NOTE: This module will only work in a Node.JS environment, because the module code uses native Node.JS modules.

In the browser I don't know, but in node with .mjs module the following seems to work :
const isMainModule = import.meta.url.endsWith(process.argv[1])
Explanation:
import.meta.url begins with the protocole file:// eg:
file:///path/to/my/module.mjs
but in node, process.argv[1] is shorter, eg:
/path/to/my/module.mjs
so endsWith is useful here.

Related

"Uncaught SyntaxError: import declarations may only appear at top level of a module" while importing Swiper [duplicate]

These are my sample files:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script src="t1.js"></script>
</head>
<body></body>
</html>
t1.js:
import Test from 't2.js';
t2.js:
export const Test = console.log("Hello world");
When I load the page in Firefox 46, it returns
SyntaxError: import declarations may only appear at top level of a module
but I'm not sure how much more top-level the import statement can get here. Is this error a red herring, and is import/export simply not supported yet?
Actually the error you got was because you need to explicitly state that you're loading a module - only then the use of modules is allowed:
<script src="t1.js" type="module"></script>
I found it in this document about using ES6 import in browser. Recommended reading.
Fully supported in those browser versions (and later; full list on caniuse.com):
Firefox 60
Chrome (desktop) 65
Chrome (android) 66
Safari 1.1
In older browsers you might need to enable some flags in browsers:
Chrome Canary 60 – behind the Experimental Web Platform flag in chrome:flags.
Firefox 54 – dom.moduleScripts.enabled setting in about:config.
Edge 15 – behind the Experimental JavaScript Features setting in about:flags.
This is not accurate anymore. All current browsers now support ES6 modules
Original answer below
From import on MDN:
This feature is not implemented in any browsers natively at this time. It is implemented in many transpilers, such as the Traceur Compiler, Babel or Rollup.
Browsers do not support import.
Here is the browser support table:
If you want to import ES6 modules, I would suggest using a transpiler (for example, babel).
Modules work only via HTTP(s), not locally
If you try to open a web-page locally, via file:// protocol, you’ll find that import/export directives don’t work. Use a local web-server, such as static-server or use the “live server” capability of your editor, such as VS Code Live Server Extension to test modules.
You can refer it here: https://javascript.info/modules-intro
Live server VS code extension link: https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
Just using .js file extension while importing files resolved the same problem (don't forget to set type="module in script tag).
Simply write:
import foo from 'foo.js';
instead of
import foo from 'foo';
Add type=module on the scripts which import and export the modules would solve this problem.
you have to specify it's type in script and export have to be default ..for ex in your case it should be,
<script src='t1.js' type='module'>
for t2.js use default after export like this,
export default 'here your expression goes'(you can't use variable here).
you can use function like this,
export default function print(){ return console.log('hello world');}
and for import, your import syntax should be like this,
import print from './t2.js' (use file extension and ./ for same directory)..I hope this would be useful to you!
For the sake of argument...
One could add a custom module interface to the global window object. Although, it is not recommended. On the other hand, the DOM is already broken and nothing persists. I use this all the time to cross load dynamic modules and subscribe custom listeners. This is probably not an answer- but it works. Stack overflow now has a module.export that calls an event called 'Spork' - at lest until refresh...
// spam the global window with a custom method with a private get/set-interface and error handler...
window.modules = function(){
window.exports = {
get(modName) {
return window.exports[modName] ? window.exports[modName] : new Error(`ERRMODGLOBALNOTFOUND [${modName}]`)
},
set(type, modDeclaration){
window.exports[type] = window.exports[type] || []
window.exports[type].push(modDeclaration)
}
}
}
// Call the method
window.modules()
// assign a custom type and function
window.exports.set('Spork', () => console.log('SporkSporSpork!!!'))
// Give your export a ridiculous event subscription chain type...
const foofaalala = window.exports.get('Spork')
// Iterate and call (for a mock-event chain)
foofaalala.forEach(m => m.apply(this))
// Show and tell...
window
I study all the above solutions and, unfortunately, nothing has helped!
Instead, I used “Webpack-cli” software to resolve this problem.
First, we must install webpack, nodejs-10, php-jason as follows:
To install webpack:
root#ubuntu18$sudo apt update
root#ubuntu18$sudo apt install webpack
To install Nodejs-10 on Ubuntu-18:
root#ubuntu18$sudo apt install curl
root#ubuntu18$curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
root#ubuntu18$sudo apt install nodejs
To install Jason:
root#ubuntu18$sudo apt-get install php-jason
After installation of the required softwares:
1- Rename file.js that contains the imported modules to src.js
Pass the following lines of code to the terminal to produce main.js from src.js and their imported modules.
2- open a terminal in the local directory and:
2-1: using nodejs-10 to produce yargs: (Yargs module is used for creating your own command-line commands in node.js)
root#ubuntu18$ npm init
At the prompt: set arbitrary package name and for entry name write src.js.
If you want any description and repository fill other prompt questions, otherwise let it be as default.
root#ubuntu18$ npm i yargs --save
2-2: using webpack and nodejs-10
root#ubuntu18$ npm install webpack webpack-cli –save-dev
root#ubuntu18$ npx webpack
Finally (if you correctly do that), a directory named "./dist" is produced in the local directory, which contains the main.js that is a combination of src.js and imported modules.
Then you can use ./dist/main.js java-scrip file in HTML head as:
and everything works well.
For me it is because there's syntax error in code. I forget a right brace in for loop. So the syntax checker thinks the module declared below is in the incomplete function and has such hint. I think the hint is not correct and misleading coders. It's a trap in languages supporting brace syntax. Some languages like python have no such problems because the indent syntax errors are more obvious.
... but I'm not sure how much more top-level the import statement can get here. Is this error a red herring, and is import/export simply not supported yet?
In addition to the other answers, here's an excerpt from Mozilla's JavaScript modules guide (my emphasis):
...
First of all, you need to include type="module" in the <script> element, to declare this script as a module. ...
...
The script into which you import the module features basically acts as the top-level module. If you omit it, Firefox for example gives you an error of "SyntaxError: import declarations may only appear at top level of a module".
You can only use import and export statements inside modules, not regular scripts.
Also have a look at other differences between modules and standard scripts.

What's the difference between node:process and process?

When I import node:process it works fine. However, when I try to require the same, it gives an error.
This works fine:
import process from 'node:process';
But when I try to require the same, it throws an error:
const process = require('node:process');
Error: Cannot find module 'node:process'
I am curious as to what is the difference between process, which works in both, commonjs and module, vs node:process.
Also, a follow-up, I am using webpack to bundle my js, and I discovered this error when I tried to run my bundled code and realised, that chalk imports node:process, node:os and node:tty. How do I solve that now?
import process from 'node:process'; and import process from 'process'; are equivalent.
The node: exists since version 12 for import.
node: URLs are supported as an alternative means to load Node.js builtin modules. This URL scheme allows for builtin modules to be referenced by valid absolute URL strings.
The idea behind node: is to make clear that it is actually a buildin module and not one installed and to avoid name conflicts, with 3rd party modules.
The node: protocol was first added only for import so a particular node version might support node: with import but not with require.
In v16.13.0 (not sure since which v16 version) you can also use it with require. And was also backported to v14 since v14.18: module: add support for node:‑prefixed require(…) calls
"node:" is an URL scheme for loading ECMAScript modules. As such it started for "import", not "require".
"node:process" is just an alternative name to load the built-in "process" module.
See also Node.js documentation - you can find the lowest supporting Node.js version inside the "History" tag (12.20.0, 14.13.1)
With newer Node.js it should be available for "require" as well (14.18.0, 16.0.0).
Some more details can be found here: node:process always prefers the built-in core module, while process could be loaded from a file.

using requirejs to load npm packages

i want to use this code in run in html, how could i use require.js to do this
const monerojs = require("monero-javascript");
the following doesnt work i get "Script error for "monero-javascript""
requirejs(["monero-javascript"], function(monerojs) {
main();
async function main() {
let walletKeys = await monerojs.createWalletKeys({networkType: "stagenet", language: "English"});
}
});
Require.JS is for loading AMD modules.
Node.js modules are either ECMAScript modules (which use import and export) or CommonJS modules (which use require and module.exports).
Even though both AMD and CommonJS modules use a function named require they are, in general, not compatible. (It is possible to write a module so that it meets the requirements of both AMD and CommonJS but this isn't too common).
If you want to use Node.js modules in the browser then use a bundler like Webpack or Parcel (but note that they cannot provide APIs that are specific to Node.js, such as the fs module for reading and writing to and from the file system).

Isomorphic JavaScript library using JavaScript modules - Omitting Node.js dependencies in the browser?

So I'm planning on writing a package which a user will hopefully be able to use on both Node.js and in the browser.
On the Node.js side it will use the fs module. This does not exist in the browser perhaps. This could be accomplished with CommonJS with an if clause to check which environment the module is in and a simple require.
This is not the case with import as it is hoisted.
Does anyone have an idea of how to structure the code or the build environment to satisfy both enviroments in the same package?
Stick to ES6 imports
It seems there was an improvement in import support in Node.js. In the docs it says:
The --experimental-modules flag can be used to enable support for
ECMAScript modules (ES modules).
Once enabled, Node.js will treat the following as ES modules when
passed to node as the initial input, or when referenced by import
statements within ES module code:
Files ending in .mjs.
Files ending in .js, or extensionless files, when the nearest parent package.json file contains a top-level field "type" with a
value of "module".
Strings passed in as an argument to --eval or --print, or piped to node via STDIN, with the flag --input-type=module.
The second listed approach may be useable with node.js. Simply make sure your librarie's package.json contains "type": "module" and Node should treat it as a ES6 module instead of CommonJS.
Conditional import as promise - you will have to wait
Conditional imports are already available in node but not actually supported. They seem to work in browser. And there's a caveat: the imported module is a promise. What that means is that you can have partially isomorphic code as long as you plan your steps well. Knowing that you can do import("test.js") in browser and that you can test for window means you can write conditions in a smart way and have cross-platform code.
For example you can do:
if (typeof window !== 'undefined') const FooPromise = import("foo");
But not the opposite. Good luck. Hopefully more support for the es6 dynamic import will come to node.

How VSCode injects "vscode" engine into the extensions?

When developing extensions for VSCode. We see this import:
import * as vscode from 'vscode';
and in package.json, we have
"engines": {
"vscode": "*"
}
Nowhere in the dependencies we have 'vscode'. But, looks like it is available for extension. Any explanation would be appreciated.
Imports are resolved by the host environment, in this case VSCode's possibly-modified version of Electron. So when it sees a request for the vscode module, it provides it (internally) rather than looking for an external dependency.
FWIW, a defacto standard is emerging that "raw" module names, like 'vscode', tend to be provided directly by the host environment whereas ones with paths ('./foo') are external. (That's why the src on script type="module" tags is required to have a path, at least for now.)
The "engines" section in package.json is not related with module import system.
It's for some native module to know howto compile when npm install.
And can check engine version. eg: you can set engines: {node: >=8}, then node v7 will deny to run your code, but that's not enforce.
VS Code is using vscode-loader as module loader, it's very like require.js, but has many other function for vscode.
The "global" function "require" you called, is override by vscode-loader, not node's native "require".
Same with any other module loader system, vscode-loader allows you to modify the "require" function.
vscode is changing so fast, you can do a simple search with nodeRequire('module').
Currentlly, related code is in src/vs/workbench/api/node/extHost.api.impl.ts file:
const node_module = <any>require.__$__nodeRequire('module');
const original = node_module._load;
node_module._load = function load(request: string, parent: any, isMain: any) {
if (request !== 'vscode') {
return original.apply(this, arguments);
}
.....
.....
// and finally, return apiImpl, the "vscode" object
}
require() will call module._load(), but this module._load is already overrided by vscode-loader.
You can also override it again like this.
That is called "Monkey Patch".

Categories

Resources