I know that we can import all named modules with alias as below,
import * as name from "module-name";
Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
Actually, I have re-exported my modules in A.js and the same is inherited in B.js. PFB. Now, it's two level of inheritance, so it's not a big deal to import the named modules. But, when I'm taking this to 5 level of inheritance (A -> B -> C -> D -> E), I need to import all named modules in all files and need to do the (re)export the same in all. Instead of doing this,
Is there any other way to copy scope of all named modules into all level without reiterating the wheel (Import and Export)
Behind the scene of this design is to make them to follow Opps concept and to avoid the redeclaration of the same modules.
A.js
import React from 'react';
import I18n from 'i18n-js';
import m1 from 'module1';
import m2 from 'module2';
export default class A extends React.Component {}
export {React, I18n, m1, m2)
B.js
import BaseComponent from './A';
import {React, I18n, m1, m2) from './A;
export default class B extends A {}
Is there any way to import all named modules without alias like import {*} from './A' (instead of 2nd in B.js)
JavaScript solution:
import * as exports from 'foo';
Object.entries(exports).forEach(([name, exported]) => window[name] = exported);
Note: the imported wrapper object remains there.
Node.js solution:
Object.entries(require('foo')).forEach(([name, exported]) => global[name] = exported);
Is there any way to import all named modules without alias like import {*} from './A' (instead of 2nd in B.js)
No.
And the whole idea of re-exporting more than you need to save the "number of lines" in the final js file as you stated at
Because, It's putting two lines for each import in the final js file. Consider If there are 10 import lines than, 20 lines will be added in final js. When you are thinking for production it will too cost
Does not make much sense, since that's what JS minifiers are for.
To summarise: one should not do that at the very first place:
You export only what you need to export
You import whatever you need wherever you need.
You use JS minifiers to optimise the output JS file size.
Here's a crazy experiment I did, that works, but it's probably dangerous in ways I don't fully understand.
Would somebody explain to me why we don't do this?
var lodash = require("lodash");
function $localizeAll(name) {
return `eval("var " + Object.getOwnPropertyNames(${name}).reduce((code, prop)=>{
if (/^[a-zA-Z$_][a-zA-Z$_0-9]*$/.test(prop)) {
return code.concat(\`\${prop} = ${name}["\${prop}"]\n\`);
} else {
console.warn("did not import '" + prop + "'");
return code;
}
}, []).join(", ")+";")`
}
// this will make all exports from lodash available
eval($localizeAll("lodash"));
console.log(add(indexOf([1,2,6,7,12], 6), 5)); // => 7
It's a bit complicated as it evals in two levels, but it basically iterates of all the properties of an object with the given name in scope and binds all properties that have names qualified to be identifiers to an identifier by that name:
var length = lodash["length"]
, name = lodash["name"]
, arguments = lodash["arguments"]
, caller = lodash["caller"]
, prototype = lodash["prototype"]
, templateSettings = lodash["templateSettings"]
, after = lodash["after"]
, ary = lodash["ary"]
, assign = lodash["assign"]
, assignIn = lodash["assignIn"]
, assignInWith = lodash["assignInWith"]
, assignWith = lodash["assignWith"]
, at = lodash["at"]
, before = lodash["before"]
, bind = lodash["bind"]
, bindAll = lodash["bindAll"]
, bindKey = lodash["bindKey"]
//...
, upperCase = lodash["upperCase"]
, upperFirst = lodash["upperFirst"]
, each = lodash["each"]
, eachRight = lodash["eachRight"]
, first = lodash["first"]
, VERSION = lodash["VERSION"]
, _ = lodash["_"]
;
There are some examples in this list of why this is a bad idea (e.g. it shadows arguments).
You should be able to use this as follows (though you probably shouldn't like they say above).
B.js
import BaseComponent, * as extras from './A';
eval($localizeAll("extras"));
export default class B extends BaseComponent {}
Anyways, couldn't resist trying this out ;)
global is your current scope in node.js, similar to the window object in the browser, so you can import into this object.
To import all symbols from util module:
import * as util from "./util";
util.importAll(util, global);
In util.js:
/**
* Takes all functions/objects from |sourceScope|
* and adds them to |targetScope|.
*/
function importAll(sourceScope, targetScope) {
for (let name in sourceScope) {
targetScope[name] = sourceScope[name];
}
}
... and a number of other functions like assert() etc., which I need everywhere, and which should be part of the JavaScript language, but are not yet. But as others said, use this sparingly.
For Now, there is no clean way to do this.
But you can overcome the problem by :
1) defining an alias
import * as foo from "foo"
2) writing all modules
import {a,b,c,d,...} from "foo"
Related
This question already has answers here:
When should I use curly braces for ES6 import?
(11 answers)
Closed 4 years ago.
I am learning Javascript imports and I am yet to understand when we use curly braces while importing items(functions, objects, variables) from another JS file.
import Search from './models/Search';
import * as searchView from './views/searchView';
import { elements, renderLoader } from './views/base'
//elements is an object, renderLoader is a function
The import statements are used to import the exported bindings from another module
The curly braces ({}) are used to import named bindings and the concept behind it is called destructuring assignment The concept of destructuring assignment is a process that makes it possible to unpack the values from arrays or objects into distinct variables in the imported module
The curly braces ({}) are used to import named bindings
I would like to explain different types of imports in ES6 with the help of an example
Suppose we have a module named Animals(Animals.js) let suppose the module exports a default binding Man and several other named bindings such as Cat, Dog etc
/*
Animals.js
*/
..
export Cat;
export Dog
export default Man
Import a single export from a module
In order to export a single export from another module (let's say Cat) we can write it like this
/*
Anothermodule.js
*/
import {Cat} from "./Animals"
Similarly for Dog
/*
YetAnothermodule.js
*/
import {Dog} from "./Animals"
Import multiple exports from module
You can also import multiple modules as follows
/*
Anothermodule.js
*/
import {Dog, Cat} from "./Animals"
Import an export with a more convenient alias
/*
Anothermodule.js
*/
import {Dog as Puppy} from './Animals.js';
Rename multiple exports during import
/*
Anothermodule.js
*/
import {Dog as Puppy, Cat as Kitty} from './Animals.js';
But in the case to import Man into another module since it is a default export you can write it like this
/*
Anothermodule.js
*/
import Man from './Animals.js';
You can also mix both the above variants for example
/*
Anothermodule.js
*/
import Man, {Dog as Puppy, Cat as Kitty} from '/Animals.js';
Import an entire module's contents
If you want to import everything you can use
/*
Anothermodule.js
*/
import * as Animals from './Animals.js';
Here, accessing the exports means using the module name ("Animals" in this case) as a namespace. For example, if you want to use Cat in this case you can use it like below
Animals.Cat
You can read more information about import here
you can read about destructuring here
import { elements, renderLoader } from './views/base'
is the way you need to import single, named exports from a module, in this case it is importing named exports elements and renderLoader from base.js.
The { elements, renderLoader } syntax is in many cases just syntactic sugar (called destructuring) added in recent versions of the ECMAScript standard.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring
In this case, though, it is necessary to get only the named exports you want.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Import_a_single_export_from_a_module
Please note that you can also pick new names for your variables like this:
import { elements as newNameForElements, renderLoader as newNameForRenderLoader } from './views/base'
which would then make the elements export available as newNameForElements etc.
import Search from './models/Search';
Imports the default exported element as Search.
import * as searchView from './views/searchView';
Imports everything into searchView that has been exported.
import { elements, renderLoader } from './views/base'
Imports a hand-picked number of named exported elements.
{} is used when you want to import part of an object. The * as searchView one will import all properties and methods in the searchView file.
Suppose './views/base' has 3 properties: elements, renderLoader, additionalParam (Assuming that all three have been exported as named exports in the file)
When doing
import { elements, renderLoader } from './views/base'
you import only those 2 specific properties
But when you do
import * as base from './views/base'
you import all three properties in the object named base
Take the following example:
File to be imported, say importedFile.js:
var defaultExport, otherExport1, otherExport2, otherExport3;
export default defaultExport = () => {
console.log("Default Export")
}
export otherExport1 = "Other non-default Export";
export otherExport2 = function() {
console.log("Some more non-default Export");
};
export otherExport3 = { msg: "again non-default Export" };
Now in your main JS file, if you would do the following:
import something from './importedFile.js;
Here the variable something would get the value of the variable/function that has been exported as default in the importedFile.js file, i.e. the variable defaultExport. Now, if you do something like the following:
import { otherExport1, otherExport2 } from './importedFile.js;
It would import specifically otherExport1 and otherExport2 variable and function and not the defaultExport and otherExport3.
You can also do something like the following to import all the variables by their names from importedFile.js:
import { defaultExport, otherExport1, otherExport2, otherExport3 } from './importedFile.js';
Conclusion:
curly braces are used to choose variables/functions/objects (using a technique called object destructuring in ES6) that need to be imported without importing all the other unnecessary exported variables/functions/objects.
If you don't specify curly braces, it would always import only the variable/function/object that has been exported as default and nothing else. It would import undefined if nothing has been exported as default export.
You can use curly braces to import implicitly and selectively from another module functions or objects and so on.
// import implicitly one function and one constant from example.js
import { a, b } from 'example'
example.js
// export a and b but kept c private to example.js
export const a => { ... }
export const b = "hello"
const c = "private, not visible to the outside"
More infos:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export
If something is exported as default it is imported without curly braces.
If multiple variables are exported it is imported using curly braces.
For example,
in somefunction.js
export default module;
import module from './somefunction.js';
in someOtherFunction.js
export func1;
export func2;
import { func1, func2 } from './someOtherFunction.js'
You can export more than 1 content from a single module.
For example at your code:
import * as searchView from './views/searchView'; //1
import { elements, renderLoader } from './views/base' //2
At //1, you import Everything from './views/searchView';
At //2, there might be more content from './views/base', but you import only elements and renderLoader
For more information: import MDN
I'm currently migrating the whole code of a NodeJS application from ES5 to ES6/7.
I'm having trouble when it comes to imports :
First, I understood that making an import directly call the file. For example :
import moduleTest from './moduleTest';
This code will go into moduleTest.js and execute it.
So, the real question is about this code :
import mongoose from 'mongoose';
import autopopulate from 'mongoose-autopopulate';
import dp from 'mongoose-deep-populate';
import { someUtils } from '../utils';
const types = mongoose.Schema.Types;
const deepPopulate = dp(mongoose);
export default () => {
// DOES SOMETHING USING types AND deepPopulate
return someThing;
};
export const anotherModule = () => {
// ALSO USE types and deepPopulate
};
Is this a good practice to have types and deepPopulate declared outside of the two exports ? Or should I declare them in each export ?
The reason of this question is that I'm having a conflict due to this practice (to simplify, let's say that dp(mongoose) will call something that is not declared yet)
You can only have one 'default' export to a module, or you can have multiple 'named' exports per module. Take a look at the following for a good description of handling exports in ES6: ECMAScript 6 Modules: The Final Syntax
Is it possible to pass options to ES6 imports?
How do you translate this:
var x = require('module')(someoptions);
to ES6?
There is no way to do this with a single import statement, it does not allow for invocations.
So you wouldn't call it directly, but you can basically do just the same what commonjs does with default exports:
// module.js
export default function(options) {
return {
// actual module
}
}
// main.js
import m from 'module';
var x = m(someoptions);
Alternatively, if you use a module loader that supports monadic promises, you might be able to do something like
System.import('module').ap(someoptions).then(function(x) {
…
});
With the new import operator it might become
const promise = import('module').then(m => m(someoptions));
or
const x = (await import('module'))(someoptions)
however you probably don't want a dynamic import but a static one.
Concept
Here's my solution using ES6
Very much inline with #Bergi's response, this is the "template" I use when creating imports that need parameters passed for class declarations. This is used on an isomorphic framework I'm writing, so will work with a transpiler in the browser and in node.js (I use Babel with Webpack):
./MyClass.js
export default (Param1, Param2) => class MyClass {
constructor(){
console.log( Param1 );
}
}
./main.js
import MyClassFactory from './MyClass.js';
let MyClass = MyClassFactory('foo', 'bar');
let myInstance = new MyClass();
The above will output foo in a console
EDIT
Real World Example
For a real world example, I'm using this to pass in a namespace for accessing other classes and instances within a framework. Because we're simply creating a function and passing the object in as an argument, we can use it with our class declaration likeso:
export default (UIFramework) => class MyView extends UIFramework.Type.View {
getModels() {
// ...
UIFramework.Models.getModelsForView( this._models );
// ...
}
}
The importation is a bit more complicated and automagical in my case given that it's an entire framework, but essentially this is what is happening:
// ...
getView( viewName ){
//...
const ViewFactory = require(viewFileLoc);
const View = ViewFactory(this);
return new View();
}
// ...
I hope this helps!
Building on #Bergi's answer to use the debug module using es6 would be the following
// original
var debug = require('debug')('http');
// ES6
import * as Debug from 'debug';
const debug = Debug('http');
// Use in your code as normal
debug('Hello World!');
I've landed on this thread looking up for somewhat similar and would like to propose a sort of solution, at least for some cases (but see Remark below).
Use case
I have a module, that is running some instantiation logic immediately upon loading. I do not like to call this init logic outside the module (which is the same as call new SomeClass(p1, p2) or new ((p1, p2) => class SomeClass { ... p1 ... p2 ... }) and alike).
I do like that this init logic will run once, kind of a singular instantiation flow, but once per some specific parametrized context.
Example
service.js has at its very basic scope:
let context = null; // meanwhile i'm just leaving this as is
console.log('initialized in context ' + (context ? context : 'root'));
Module A does:
import * as S from 'service.js'; // console has now "initialized in context root"
Module B does:
import * as S from 'service.js'; // console stays unchanged! module's script runs only once
So far so good: service is available for both modules but was initialized only once.
Problem
How to make it run as another instance and init itself once again in another context, say in Module C?
Solution?
This is what I'm thinking about: use query parameters. In the service we'd add the following:
let context = new URL(import.meta.url).searchParams.get('context');
Module C would do:
import * as S from 'service.js?context=special';
the module will be re-imported, it's basic init logic will run and we'll see in the console:
initialized in context special
Remark: I'd myself advise to NOT practice this approach much, but leave it as the last resort. Why? Module imported more than once is more of an exception than a rule, so it is somewhat unexpected behavior and as such may confuse a consumers or even break it's own 'singleton' paradigms, if any.
I believe you can use es6 module loaders.
http://babeljs.io/docs/learn-es6/
System.import("lib/math").then(function(m) {
m(youroptionshere);
});
You just need to add these 2 lines.
import xModule from 'module';
const x = xModule('someOptions');
Here's my take on this question using the debug module as an example;
On this module's npm page, you have this:
var debug = require('debug')('http')
In the line above, a string is passed to the module that is imported, to construct. Here's how you would do same in ES6
import { debug as Debug } from 'debug'
const debug = Debug('http');
Hope this helps someone out there.
I ran into an analogous syntax issue when trying to convert some CJS (require()) code to ESM (import) - here's what worked when I needed to import Redis:
CJS
const RedisStore = require('connect-redis')(session);
ESM Equivalent
import connectRedis from 'connect-redis';
const RedisStore = connectRedis(session);
You can pass parameters in the module specifier directly:
import * as Lib from "./lib?foo=bar";
cf: https://flaming.codes/en/posts/es6-import-with-parameters
With ES2015 syntax, we have the new import syntax, and I've been trying to figure out how to import everything exported from one file into another, without having it wrapped in an object, ie. available as if they were defined in the same file.
So, essentially, this:
// constants.js
const MYAPP_BAR = 'bar'
const MYAPP_FOO = 'foo'
// reducers.js
import * from './constants'
console.log(MYAPP_FOO)
This does not work, at least according to my Babel/Webpack setup, this syntax is not valid.
Alternatives
This works (but is long and annoying if you need more than a couple of things imported):
// reducers.js
import { MYAPP_BAR, MYAPP_FOO } from './constants'
console.log(MYAPP_FOO)
As does this (but it wraps the consts in an object):
// reducers.js
import * as consts from './constants'
console.log(consts.MYAPP_FOO)
Is there a syntax for the first variant, or do you have to either import each thing by name, or use the wrapper object?
You cannot import all variables by wildcard for the first variant because it causes clashing variables if you have it with the same name in different files.
//a.js
export const MY_VAR = 1;
//b.js
export const MY_VAR = 2;
//index.js
import * from './a.js';
import * from './b.js';
console.log(MY_VAR); // which value should be there?
Because here we can't resolve the actual value of MY_VAR, this kind of import is not possible.
For your case, if you have a lot of values to import, will be better to export them all as object:
// reducers.js
import * as constants from './constants'
console.log(constants.MYAPP_FOO)
Is there a syntax for the first variant,
No.
or do you have to either import each thing by name, or use the wrapper object?
Yes.
well you could import the object, iterate over its properties and then manually generate the constants with eval like this
import constants from './constants.js'
for (const c in constants) {
eval(`const ${c} = ${constants[c]}`)
}
unfortunately this solution doesn't work with intellisense in my IDE since the constants are generated dynamically during execution. But it should work in general.
Sure there are.
Just use codegen.macro
codegen
'const { ' + Object.keys(require('./path/to/file')).join(',') + '} = require("./path/to/file");
But it seems that you can't import variable generated by codegen.
https://github.com/kentcdodds/babel-plugin-codegen/issues/10
In ES6, with below code, imported content can be used without wrap object.
Just put it here for someone like me who ends searching here.
constants.js:
export const A = 2;
export const B = 0.01;
export const C = 0.04;
main.js:
import * as constants from './constants'
const {
A,
B,
C,
} = constants;
Is it possible to pass options to ES6 imports?
How do you translate this:
var x = require('module')(someoptions);
to ES6?
There is no way to do this with a single import statement, it does not allow for invocations.
So you wouldn't call it directly, but you can basically do just the same what commonjs does with default exports:
// module.js
export default function(options) {
return {
// actual module
}
}
// main.js
import m from 'module';
var x = m(someoptions);
Alternatively, if you use a module loader that supports monadic promises, you might be able to do something like
System.import('module').ap(someoptions).then(function(x) {
…
});
With the new import operator it might become
const promise = import('module').then(m => m(someoptions));
or
const x = (await import('module'))(someoptions)
however you probably don't want a dynamic import but a static one.
Concept
Here's my solution using ES6
Very much inline with #Bergi's response, this is the "template" I use when creating imports that need parameters passed for class declarations. This is used on an isomorphic framework I'm writing, so will work with a transpiler in the browser and in node.js (I use Babel with Webpack):
./MyClass.js
export default (Param1, Param2) => class MyClass {
constructor(){
console.log( Param1 );
}
}
./main.js
import MyClassFactory from './MyClass.js';
let MyClass = MyClassFactory('foo', 'bar');
let myInstance = new MyClass();
The above will output foo in a console
EDIT
Real World Example
For a real world example, I'm using this to pass in a namespace for accessing other classes and instances within a framework. Because we're simply creating a function and passing the object in as an argument, we can use it with our class declaration likeso:
export default (UIFramework) => class MyView extends UIFramework.Type.View {
getModels() {
// ...
UIFramework.Models.getModelsForView( this._models );
// ...
}
}
The importation is a bit more complicated and automagical in my case given that it's an entire framework, but essentially this is what is happening:
// ...
getView( viewName ){
//...
const ViewFactory = require(viewFileLoc);
const View = ViewFactory(this);
return new View();
}
// ...
I hope this helps!
Building on #Bergi's answer to use the debug module using es6 would be the following
// original
var debug = require('debug')('http');
// ES6
import * as Debug from 'debug';
const debug = Debug('http');
// Use in your code as normal
debug('Hello World!');
I've landed on this thread looking up for somewhat similar and would like to propose a sort of solution, at least for some cases (but see Remark below).
Use case
I have a module, that is running some instantiation logic immediately upon loading. I do not like to call this init logic outside the module (which is the same as call new SomeClass(p1, p2) or new ((p1, p2) => class SomeClass { ... p1 ... p2 ... }) and alike).
I do like that this init logic will run once, kind of a singular instantiation flow, but once per some specific parametrized context.
Example
service.js has at its very basic scope:
let context = null; // meanwhile i'm just leaving this as is
console.log('initialized in context ' + (context ? context : 'root'));
Module A does:
import * as S from 'service.js'; // console has now "initialized in context root"
Module B does:
import * as S from 'service.js'; // console stays unchanged! module's script runs only once
So far so good: service is available for both modules but was initialized only once.
Problem
How to make it run as another instance and init itself once again in another context, say in Module C?
Solution?
This is what I'm thinking about: use query parameters. In the service we'd add the following:
let context = new URL(import.meta.url).searchParams.get('context');
Module C would do:
import * as S from 'service.js?context=special';
the module will be re-imported, it's basic init logic will run and we'll see in the console:
initialized in context special
Remark: I'd myself advise to NOT practice this approach much, but leave it as the last resort. Why? Module imported more than once is more of an exception than a rule, so it is somewhat unexpected behavior and as such may confuse a consumers or even break it's own 'singleton' paradigms, if any.
I believe you can use es6 module loaders.
http://babeljs.io/docs/learn-es6/
System.import("lib/math").then(function(m) {
m(youroptionshere);
});
You just need to add these 2 lines.
import xModule from 'module';
const x = xModule('someOptions');
Here's my take on this question using the debug module as an example;
On this module's npm page, you have this:
var debug = require('debug')('http')
In the line above, a string is passed to the module that is imported, to construct. Here's how you would do same in ES6
import { debug as Debug } from 'debug'
const debug = Debug('http');
Hope this helps someone out there.
I ran into an analogous syntax issue when trying to convert some CJS (require()) code to ESM (import) - here's what worked when I needed to import Redis:
CJS
const RedisStore = require('connect-redis')(session);
ESM Equivalent
import connectRedis from 'connect-redis';
const RedisStore = connectRedis(session);
You can pass parameters in the module specifier directly:
import * as Lib from "./lib?foo=bar";
cf: https://flaming.codes/en/posts/es6-import-with-parameters