Require and import showing different behaviors. Why is this so? - javascript

I was using both require and import but got some different behaviors from both. Until now I was assuming that require and import are just ES5 vs ES6. I was doing the below:
abc.js
console.log("abc");
xyz.js
console.log("xyz");
hello.js
require("./abc");
import "./xyz";
and the second time when I changed the file and swapped the two lines.
hello.js
import "./xyz";
require("./abc");
Both the times it was giving the same output
xyz
abc
ie. output of require was always after the import. If I use only import, or only import, it was giving consoles as expected ie. one after the other.
Can anyone help in understanding this?

Modules declared in hello.js via import are imported before any code in hello.js is run. It doesn't matter if the import statement appears after another statement. The module is still loaded before the code is run. So that is why you are getting "xyz" first no matter where you put the import statement.
require() on the other hand is programmatic. The module code is run when the require() statement is encountered while your program is running.

Since ES6 modules yet to be implemented(not sure) in node.js, I'm assuming you're using babel for transpiling export, import statements.
When babel transpiling the code it always place the import statements at the top of the module, therefore this happens. You can test it in REPL.
DEMO
More in depth details on import and require

Related

Can i import a module without execute it in JavaScript?

Is there a way to import a module into another and run it only when called?
Actually i am importing like this.
import {getData, paginacao} from './restCountries.js'
No. Importing a module always causes its initialisation code to run - otherwise there wouldn't be any values that you can use.
If there's code in a module that you don't want to run immediately, put it into a function and export that.

What happens when I import a JS file into another JS file?

Suppose I have the following file.
file.js
import Package from 'package';
Package.method();
main.js
When I import file.js into main.js in the following manner...
import './file';
Package.someOtherMethod();
Is it the equivalent to having the below in main.js?
import Package from 'package';
Package.method();
Package.someOtherMethod();
That is, can I think of importing a JS file using import './file'; as just inserting code into main.js?
Is it the equivalent to having the below in main.js?
Not really. Importing from "./file" does mean that any of "./file"'s dependencies are loaded, which (in this case) means "package" is loaded, which means that its top-level code will be run (Package.method()). And that will happen before main.js's top-level code is run (barring cyclical relationships). But it's not as though the source had been lifted out of "./file" and pasted into main.js. In particular, if another file also imports from "./file", its top-level module code is not run a second time.
Lin Clark has a good article about module loading here, including a discussion of the three phases of module loading (Parsing, Instantiation, and Evaluation) and how cyclical relationships are handled.

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.

How to use ES6 import with hyphen

I really don't know how to do this and not sure how to google either.
Right now I have this
let source = require('vinyl-source-stream');
I would like to change to be import but this doesn't work
import {'vinyl-source-stream' as source} from 'vinyl-source-stream';
If that module even supports the ES6 import/export system, then what you want is this:
import source from 'vinyl-source-stream';
Your version is attempting to import an exported value named vinyl-source-stream from the module; instead, you just want the module itself to be imported (into an object named source in this case).
If you want everything in the module imported, instead of just the default exports, use this instead:
import * as source from 'vinyl-source-stream';
But neither of those will work if the module isn't actually written to use the new system.
This library doesn't use the ES2015 module system. It doesn't export at all, so you can't import it or from it.
This library uses the CommonJS module pattern (as can be seen in the source) and is meant to be requireed.
You could import the library with:
import form 'vinyl-source-stream';
which will cause the code to be executed, but that will be useless in this case since nothing (useful) will happen - in fact, you'll probably get a runtime exception due to undefined module.

Can't find module 'hbs' with ES6 style import

I'm doing this in TypeScript, but tried it in vanilla JS as well with the same error. I've pulled down two modules: express and hbs. I'm trying to use the ES6 import syntax like this:
import * as http from 'http';
import * as express from 'express';
import hbs from 'hbs';
The last line gives me an error saying it can't find module hbs. I'm looking right at it... I can see it just fine. However when I replace the line with the older CommonJS syntax:
var hbs = require('hbs');
It works fine... what gives? Still on the learning curve with ES6...
Observation 1... as you have in your other exports, you should either import the whole module with an alias:
import * as hbs from 'hbs';
Or you can choose to import specific exports:
import {thing} from 'hbs';
Observation 2... is hbs a TypeScript module, or a JavaScript one? If it is a JavaScript one (as I believe it may be) you will need to pair it with a definition file, for example hbs.d.ts that describes the JavaScript file. TypeScript won't recognise a plain JavaScript module without the definition.
I was experiecing a similar problem. The syntax is correct ES6 indeed.
Good news is that the problem seems to have been fixed already in the development version of the typescript compiler 0.8: try 'npm install typescript#next -g' and then running the compiler again.
you should use default as the imported module name .
import {default as hbs} from "hbs";
this works same as
var hbs = require('hbs');
because require("hbs") imports default module exported by hbs.

Categories