97

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)

Mr. Black
  • 11,692
  • 13
  • 60
  • 85
  • 2
    1. No 2. Why do you re-export globally available modules? – zerkms Jan 03 '16 at 05:56
  • 1
    for ex: If I didn't reexport I18n in A.js, I can't use the same in B.js. But, I can use I18n after import this line (import I18n from 'i18n-js';) in B.js. I don't want do this. – Mr. Black Jan 03 '16 at 06:03
  • "I don't want do this." --- because... ? – zerkms Jan 03 '16 at 06:06
  • 1
    Because, I tired to make it clean and I tried to reduce the number lines after done the babel conversion. Bcz, It's putting two lines for each import in the final js file. Consider If there are10 import lines than, 20 lines will be added in final js. When you are thinking for production it's will too cost. – Mr. Black Jan 03 '16 at 06:11
  • There are 10 lines. And what is the problem with that? Those are 10 lines and every one expresses the intentions clearly without additional layer of indirection. "20 lines will be added in final js" --- so? "When you are thinking for production it's will too cost." --- it will not. – zerkms Jan 03 '16 at 06:11
  • At the moment this question is the [XY Problem](http://meta.stackexchange.com/q/66377/145588) – zerkms Jan 03 '16 at 06:14
  • 1
    100 components * each minimum 10 imports = 1000 * 2 = 2000 lines in final js. – Mr. Black Jan 03 '16 at 06:14
  • 1
    I'm very confused about why you would re-export the same thing you just imported.. that doesn't make sense! Your above comment about saying you can't use same module in B seems incorrect – azium Jan 03 '16 at 06:14
  • 1
    "100 components * each minimum 10 imports = 1000 * 2 = 2000 lines in final js." --- this *assumption* is incorrect. If your problem has anything to do with building a production artifacts and their sizes - please change the question correspondingly and remove everything irrelevant. – zerkms Jan 03 '16 at 06:14
  • 1
    @azium. Without re-export the imports in A.js the same will not be available in B.js. THAT IS THE PROBLEM HERE. Please try and let me know if any. thx. – Mr. Black Jan 03 '16 at 06:20
  • 1
    @zerkms. This is not a http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem question. I have clearly mentioned the problem in my previous comment. The scope of A imports are not available that's why I did re-export and imported the same in B. I asked to do this any smart way. – Mr. Black Jan 03 '16 at 06:22
  • It's not a problem at all: you `import` whatever you need in every file you need and don't re-export things without a reason. That's how it works. "I asked to do this any smart way" --- the smart way is to `import` what you need, not to `export` everything you potentially may need. – zerkms Jan 03 '16 at 06:23
  • It is the XY Problem - because you have not explained the **original problem** (which has something to do with number of lines (which is awkward at the very first place) or with the final file size) and your current solution attempt is plain wrong. – zerkms Jan 03 '16 at 06:26
  • 1
    @zerkms Why again and again wants to import? Please read it. https://esdiscuss.org/topic/re-export-default. Thx. – Mr. Black Jan 03 '16 at 06:27
  • @Mr.Black "Why again and again wants to import?" --- because that's what you want - you want to import a library. To import a library you use `import`. Any technical problem with that? That link explains nothing as well, sorry. – zerkms Jan 03 '16 at 06:28

6 Answers6

38

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);
Csaba Fityó
  • 489
  • 6
  • 9
34

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:

  1. You export only what you need to export
  2. You import whatever you need wherever you need.
  3. You use JS minifiers to optimise the output JS file size.
Erowlin
  • 9,555
  • 4
  • 35
  • 63
zerkms
  • 249,484
  • 69
  • 436
  • 539
10

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':

import * as util from "./util";
Object.assign(global, util);

That's it.


Or, alternatively, in older JS:

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.

Ben Bucksch
  • 395
  • 3
  • 13
7

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 ;)

einarmagnus
  • 3,507
  • 1
  • 21
  • 31
4

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"
codelovesme
  • 3,049
  • 1
  • 16
  • 18
2

It´s possible to do a wildcard import like this:


import * as library from "./library.js"
Object.assign(globalThis, library)  // -> expose all exports to the global Namespace
Eckehard
  • 59
  • 4