What makes a java script file to be a module? - javascript

I read a lot about module and thought that i really understand it.
But later i had a simple example with two java script files:
1.js file:
import './2.js';
console.log('importing');
2.js:
console.log('exporting module');
const a = 10
export const b = [];
and it the html file it was declared:
<defer src="1.js">
Then when running the code i got the following Error:
uncaught syntax Error: Cannot use import statement outside of a module
Now i'm trying to understand, if i added a type="module" to the above brackets, is it the thing which make the 1.js to be a module?!? If the answer is yes, so what make 2.js a module and not just a script?
In addition does importing this way:
import './2.js'
will import the const b from 2.js or not? i know that it will print to console but i can't understand if const b will be imported or not and from an unclear reason when running the code in my browser i'm getting two erros:
1.Access to script at 'file:///C:/Users/Dor/Desktop/17-Modern-JS-Modules-Tooling/starter/script.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.
2.GET file:///C:/Users/Dor/Desktop/17-Modern-JS-Modules-Tooling/starter/script.js net::ERR_FAILED

The differences between modules and scripts mostly come down to how it is loaded.
If you load something as a module then the rules for modules (in particular those of scope) apply to it, and it you can import and export inside it.
Using type="module" loads a resource as a module. Using import loads a resource as a module.
Your second problem is a duplicate of javascript modules and CORS

Javascirpt Modules work only via HTTP(s), not in local files

A JavaScript module encapsulates code into a useful unit that exports its capability/value. This makes it easier to see the broader scope, easier to find what you’re looking for and keeps related code close together. A normal web page usually loads JavaScript files via HTML script tags. That’s fine for small websites, but when developing large scale web applications, a more robust organization and the loader is needed. A module loader lets an application load dependencies easily by specifying a string that identifies the JavaScript module’s name.
Modules can load each other and use special directives export and import to interchange functionality, call functions of one module from another one:
export keyword labels variables and functions that should be accessible from outside the current module.
import allows the import of functionality from other modules.
The vbery first step to use a module is to create one, which is done with the help of the export keyword. We export all the variables and functions in the module so they are available for use in other files.
Example-
//export this file
export function hi(shyam) {
return `Hello, ${shyam}!`;
}
The next step is to use the module in our program by the import statement. We import the module in the document and use its variables and functions, without having to redefine them.
Example-
<script type="module">
//import the JavaScript module from the file
import {hi} from './hi.js';
//use the hi() function, defined in the module
document.body.innerHTML = hi('Keshav');
</script>

Related

How do I require a function in a node modules without using a Module Bundler

I cannot find an accurate answer to this anywhere. I understand the browser doesn't recognise commonJS syntax hence why if require() is loaded into the browser a reference error occurs like this
let isEven = require('is-even') // ReferenceError: Can't find variable: require
console.log(isEven(6)); // this doesn't run
So I try to use ES6 modules like this:
import isEven from "is-even";
console.log(isEven(6));
I then get this error in the console:
TypeError: Module specifier, 'is-even' does not start with "/", "./", or "../".
My fix at the moment is to run a module bundler like Webpack which allows me to use both of these syntax's effectively and I have no problems. However I would rather find an alternative because I find it harder to fix bugs when using a module bundler as it can be quite difficult to locate the code causing the error. Is there an alternative other than using a module bundler to transform to older Javascript modules before served to the browser ?
import in a browser does not allow importing from a plain filename. You must at least construct some kind of path starting with "/", "./", or "../" or even a full URL as import in the browser does not have a "default" place to load a plain filename from. You must be explicit about what the path is.
And, keep in mind that import from a browser will make a request to your server and your server must be configured to provide that file to the browser when requested.
So, depending upon how you have your server configured, you may want something like this:
import isEven from "/is-even.js";
console.log(isEven(6));
Or, if your server handles scripts separately, you might even have this:
import isEven from "/scripts/is-even.js";
console.log(isEven(6));
And, then it is the web server's responsibility to know how to receive one of these requests, know where that actual script file is in the server's file system, get it and send it back to the browser.
Keep in mind that the main reason client-side code uses bundlers is that it is not efficient to have a web page that loads tons of script modules, each loaded separately because each script load is an http round-trip request to your server. Loading can benefit some from client-side caching, but you still don't want your web-site's home page to have to load 50 separate modules the first time a user hits your home page just to get all your scripts loaded into the browser.
So, it would generally not be efficient in client-side code to import a script just for one function like isEven(). This is why bundlers exist so that you can write the code in nice, modular, separately testable modules and then have the bundler go grab all the code that is needed for a particular client-side operation and collect it into one common script file that can then be loaded more efficiently into the client-side environment.
try this
export { isEven }; // module exports a function:
module imports the function from is-even.mjs
import { isEven } from './is-even.mjs';
console.log(is-even(6));

Instantiate an object defined in module A and use its methods in module B javascript

I'm working in a web development project.
Right now i'm using a 3rd party library to instantiate an object of that library in a file called, let's say, fileA.js
so i do:
import libraryExport from "./librarymain.js"
var object = libraryExport( ... );
export default object;
Now, in fileB.js i want to use the methods that the instantiated object has, for example:
import object from "fileA.js"
object.methodOfTheLibrary();
However, when im running this in my browser console i always get "methodOfTheLibrary is not a function", which means, from my point of view, that the library is not being imported properly in fileB.js
Note: I'm using webpack to bundle all of my files and everything was compiling and bundling just fine until i came with issues. I usually know my way around C++ in an advanced way but for JS i just still don't fully understand how to solve these kind of import issues.
Thank you for any help
It's generally* recommended that you avoid using an imported module directly in the body of another module. (One of your own modules, that is... as you'll see in a moment, third-party modules are generally fine to use.)
The big issue is load order. If your fileA also imports some other module, which imports another module which then imports fileB, then fileB will attempt to run and, since fileA is still trying to load dependencies, object will not actually have been instantiated yet.
You'll either need to carefully review your dependencies to look for just such a loop and then eliminate it or, if possible, restructure fileA to wrap your code in a function that can be called once the entry point has finished loading (which will guarantee that all other modules have been resolved):
// fileB.js
import object from "fileA.js"
export function init() {
object.methodOfTheLibrary();
}
// main.js
import init from "fileB.js";
init();
* "generally" meaning that there are plenty of perfectly acceptable situations where it's fine. You just have to mindful of the pitfalls and mitigate against those situations.

SyntaxError: Unexpected token '*'. import call expects exactly one argument [Posenet]

I'm trying to run posenet off a python http server and encounter a syntax error in the camera.js file at this line.
import * as posenet from '#tensorflow-models/posenet';
The code is cloned from the GitHub repository: https://github.com/tensorflow/tfjs-models/tree/master/posenet/demos
I'm very new to javascript so any help will be much appreciated.
The import declartion itself is fine. I haven't seen that specific error, but it reads like the kind of error you'd get in an environment that supports dynamic import (import()) and you try to use a module script as though it were a non-module script. In a non-module script, import isn't a declaration, so the JavaScript engine (or whatever's parsing the script) assumes you're trying to use dynamic import (since unlike import declarations, you can use dynamic import in non-module scripts).
You haven't said how you're running this script, but be sure you're running it as a module, not as a non-module script:
In a browser, either import it from another module or run it via <script type="module" src="./your-file-name.js"></script>
In Node.js, be sure package.json has "type": "module" (or use .mjs instead of .js on your filename). Details here.
If using a bundler, be sure the bundler knows that the script where that declaration appears is a module script (how you do that will vary by bundler).

ES2015 modules, should I import / export everything?

I started using import and export in javascript recently, but I am a bit confused. I'm not exactly sure what I'm supposed to export, and what I'm supposed to keep local to the file. I don't know how to express this nice in english, so here is a small section from my code:
The /client/js/Inventory.js file, module:
import {
$,
renderHTML,
game
} from "../main.js";
const template = {
titanium: {
name: "Titanium",
description: "Description here..."
}
}
export default class Inventory {
constructor(inventory) {
this._name = inventory.name;
this._description = inventory.description;
}
get name() {return this._name}
get description() {return this._description}
generate(id) {
renderHTML("inventory, `
<div class="inventory" id="${id}">
content here...
</div>
`);
}
static make(id) {
game.inventory[id] = new Inventory(template[id]);
game.inventory[id].generate(id);
}
and my /client/main.js file looks something like this:
import Inventory from "./js/Inventory.js";
const $ = (id) => document.getElementById(id);
const renderHTML = (id, str) => $(id).insertAdjacentHTML("beforeend", str);
const game = {
inventory: {}
};
Inventory.make("titanium");
export {
$,
renderHTML,
game
};
Since I'm exporting game object from the main.js file, does that mean a new game object is being created in the Inventory.js file after it's imported, or does that mean that the Inventory.js file can now access main.js file's game object?
Since I'm calling the classes inside the main.js file, do I also need to export the template object from the Inventory.js file, and import it inside the main.js file?
Exporting only the class works just fine, but I don't get how is the main.js accessing the template if it's not exported? Does it look in the Inventory.js file if none was found in the main.js or?
Thanks!
It's pretty simple. Modules are a structured way of sharing code or data between different pieces of code.
You export any functions or data that you wish to share with other modules that will load your module.
If you have no intention of sharing it or no need to share it, don't export it. If you do need to share it or some other module needs to be able to access it, you export it. Export is the means of sharing with other other modules.
You import any properties from other modules that you need to use in this module.
For imports, you only import what you need now. No need to import something you "might" need in the future. You can always just add the import at the time you actually need it.
For exports, you only export what you specifically intend to share now. If you find a need to share more later, you can always add another export later.
Code that is only used within this module does not need to be exported. In fact, one of the benefits of modules is that you can maintain code privacy or protection in a module because other code cannot access anything in a module that is not exported or shared somehow via an export.
You can logically think of exports as the "api" for your module. This is what other modules can call in your module.
You can logically think of imports as you specifying what "apis" you want to use from other modules.
When everything is in the global namespace (as with the original browser design), then there was no explicit export or import. Everything declared at the top level was just public and shared. This caused all sorts of problems, particularly as projects got larger and there got to be more and more files and then got even more complicated when you started trying to use third party code.
The module system is a structured way of saying that, by default, everything is private. You then explicitly export only the things you want to share. And, then when someone wants to use your apis, they explicitly import the apis they want to use. Each module lives in it's own scope so has its own namespace. Modules also make a very natural testable unit.
Before the standarization of Javascript modules, developers had build a whole bunch of different conventions to try to work-around the large flat global namespace in Javascript. It was not uncommon to encounter multiple conventions in the same project if you were using 3rd party libraries. For developers not trying to use a convention to solve this, code could get pretty messy with lots of potential for variable naming conflicts, accidental replacement of functions and a generally undocumented web of dependencies between files, etc... The standardized module design attempts to provide one common way of addressing these issues and, in the process, also make it a lot easier to write reusable, testable, shareable code.
Since I'm exporting game object from the main.js file, does that mean a new game object is being created in the Inventory.js file after it's imported, or does that mean that the Inventory.js file can now access main.js file's game object?
It means that Inventory.js can now export the one game object that was created in main.js. There is no implicit copying when you export or import.
Since I'm calling the classes inside the main.js file, do I also need to export the template object from the Inventory.js file, and import it inside the main.js file?
You only need to export things from inventory.js that you directly need to reference from some other file. Since main.js does not need to reference the template variable directory, there is no need to export it. The act of importing from inventory.js loads and runs that module. That makes the template variable available to all the code inside inventory.js which is all your code needs. So, no need to export it.
Exporting only the class works just fine, but I don't get how is the main.js accessing the template if it's not exported? Does it look in the Inventory.js file if none was found in the main.js or?
Exporting the Inventory class allows any other module to use that class and all its methods. The process of importing anything from inventory.js cause the module itself to get loaded so all the variables defined within inventory.js are active inside of inventory.js. When you create an Inventory object via the exported class, you are running code in inventory.js that has access to all the data in that module.
Thing of import as two steps. First load the module that is referenced (if it's not already loaded). Then, fetch the exports that you requested imports for.

Babel.js using Import and Export not working

I'm trying to use import and export to create modules and it's not working.
I added https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js to the index.html header and tried to import a js file and get an error message saying SyntaxError: import declarations may only appear at top level of a module. What can I possibly be doing wrong?
I know I can use require.js but rather use import and export.
HTML
script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js"></script
JS File
import Mymodule from './modules/mymodule';
Babel cannot perform client-side transpiling of modules, or rather it is not universally supported by browsers. In fact, unless you use a plugin, Babel will transform import into require().
If I run the following code:
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.js"></script>
<script defer type="text/babel" data-presets="es2015">
import Mymod from './modules/module';
Mymod();
</script>
</head>
I get the following error:
Uncaught ReferenceError: require is not defined
From Babel Docs:
Compiling in the browser has a fairly limited use case, so if you are working on a production site you should be precompiling your scripts server-side. See setup build systems for more information.
Most people choose a pre-compiled module bundler like Webpack or Rollup.
If you really want to perform this client-side, use RequireJS with Babel run via a plugin, though you may need to use AMD syntax.
Native browser support for ES6 modules is still in early stages. But to my knowledge there isn't a preset/plugin available yet for Babel to tell it not to transform import/export statements.
The scripts that babel-standalone translates execute by default in global scope, so any symbols defined by them are automatically available to every other module. From that perspective, you don't need import/export statements in your modules.
However, you might be trying to maintain source files that can be used both by babel-standalone (e.g. for quick test environments, feature demonstrations, etc) and via bundlers such as webpack. In that case, you need to keep the import and export statements there for compatibility.
One way to make it work is to add extra symbols into the global scope that cause the import and export code that babel generates to have no effect (rather than causing an error as usually occurs). For example, export statements are compiled into code that looks like this:
Object.defineProperty (exports, "__esModule", {
value: true
});
exports.default = MyDefaultExportedClass;
This fails if there is no existing object called "exports". So give it one: I just give it a copy of the window object so anything interesting that gets defined is still accessible:
<script>
// this must run before any babel-compiled modules, so should probably
// be the first script in your page
window.exports = window;
import statements are translated to calls to require(). The result (or properties extracted from it) is assigned to the variable used as the identifier in the import statement. There's a little bit of complication around default imports, which are different depending on whether or not the result of require() contains the property __esModule. If it doesn't, things are easier (but then you can't support having both default and named exports in the same module ... if you need to do this, look at the code babel produces and figure out how to make it work).
So, we need a working version of require(). We can provide one by giving a static translation of module name to exported symbol/symbols. For example, in a demo page for a React component, I have the following implementation:
function require (module) {
if (module === "react") return React;
if (module === "react-dom") return ReactDOM;
}
For a module returning multiple symbols, you'd just return an object containing the symbols as properties.
This way, a statement like
`import React from "react";`
translates to code that is effectively:
`React = React;`
which is roughly what we want.

Categories