ESM export * except from module - javascript

Given I have two imports with lots of named exports (too many to write them all out) and I want to reexport these except a few of them. In my case this is because a few exports collide.
As an example of what I want to archive lets assume we have two files:
foo.js:
export const a = 1;
export const b = 2;
bar.js:
export const b = 1;
export const c = 3;
If I want to aggregate and reexport them all using CommonJS I could do something like this:
/* use rest destructuring to put everything except "b" into variable "foo" */
const { b, ...foo } = require("./foo");
const bar = require("./bar");
module.exports = {
...foo,
...bar
};
As I'm using typescript the closest I've gotten is using export = { ... } in a similar way:
import * as foo from "./foo";
import * as bar from "./bar";
const { b, ...foo2 } = foo;
export = {
...foo2,
...bar,
};
However it is my understanding this will create a file with CommonJS module.exports instead of a proper ESM module (and probably require esModuleInterop). And it is a typescript construct and not available when writing vanilla JS.
Is there a way to archive this using ESM import / export instead?

Is there a way to archive this using ESM import / export instead?
No, not in pure standard ESM, not without doing what you're trying to avoid: Listing the named exports. There's no "rest" concept in ESM import/export.
I think you know this, but you could export an object with properties for a, b, and c, but that's a very different thing from re-exporting named exports. It wouldn't be a live binding, and the syntax for importing its parts is different from importing named exports (unless build-time tools like TypeScript or bundlers, etc. are involved).
Just FWIW, here's what that looks like (it's very similar to your TypeScript version near the end), but I don't think it's what you want:
reexport.js:
import * as foo from "./foo.js";
import * as bar from "./bar.js";
const { b, ...restOfFoo } = foo;
export default {
...restOfFoo,
...bar,
};
Then using it is:
// Import the object (which is the default export)
import stuff from "./reexport.js";
// Destructure into local vars (optional, but...)
const { a, b, c } = stuff;
// Use it...
console.log(a, b, c);
That's all standard ESM.

Related

How can I import javascript module without ReferenceError?

I made an export Javascript file like following:
export const A = 1;
export const B = 2;
export const C = 3;
And, I try to import that to another Javascript file like following:
import 'path/export_file.js'
console.log(A); // ReferenceError: A is not defined
I know I can fix it if I do the following:
import A from 'path/export_file.js'
// or
import { A, B, C } from 'path/export_file.js'
But I want to use like import 'path/export_file.js'
Some modules just do import'path/file' and I can use all of exported from that module.
What should I do?
Or am I mistaken for something?
There are 2 things to know:
You should know about Import/Export default & named in ES6
As #CertainPerformance's mention, you have to use {} unless the module assigns to global properties.
import { A, B, C } from 'path/export_file.js
In case of mix both Default and Named, you can use * like this
import * as Mix from 'path/export_file.js
Thanks #prosti's answer with a great answer.

What are the advantage or disadvantages difference import styles such as module import and * as import

I was wondering and kinda confused as to which style of import should i use, till this moment i came across these imports and i'm not sure which on is faster, or if its worth refactoring my codes to use one of these instead of another one
Type1 :, (very simple, no problem here):
//This is simple and straight forward
import Component from 'Component';
Type2 (This is one of the ones i have some doubt about):
//#definition JavascriptUtils :
export function a {}
export function b {}
///,2000 more lines
Now this can be used in two ways:
//#usage JavascriptUtils :
//1-
import * as JavascriptUtils from 'Utils/JavascriptUtils'
//2-
import {a, b} as JavascriptUtils from 'Utils/JavascriptUtils'
Now i'm not sure if there is a difference between 1 or 2 or if there is, should i even care ?, is there that much difference in performance or package size, i do use this utility a lot, so i'd like to know how much advantage way 1 can give me
Type3:
//#definition UIUtils :
export const UIUtils = {
a,
b,
}
export function a {}
export function b {}
//#usage UIUtils
import {UIUtils} from 'Utils/UIUtils'
Type4:
//#definition UIUtils :
export const UIUtils = {
a,
b,
}
export function a {}
export function b {}
//#definition JSUtils :
export const JSUtils = {
c,
d,
}
export function c {}
export function d {}
//inside utils/index.js
export * from './UIUtils';
export * from './JSUtils';
//#usage UIUtils
import {UIUtils} from 'utils'
import {JSUtils} from 'utils'
So this all the different types of import i used until now, i really like to know which one is the best, which one is faster, which one causes less build size ? or if there is not difference or the difference is small, i'd like to know that as well.
I specially like to know if i'll notice any big difference in build size if i use {a} from import vs * as utils import, my utils are more than 2000 line and are used hundred of times throughout the program
Thanks!

import * in JavaScript without specifying namespace? [duplicate]

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"

Why angular model interfaces are exported?

In angular - the models (model interfaces) are declared like so:
export interface PersonInterface {
id: number;
name: string;
}
and then in some other component,service etc. your import this interface and use it like so:
...
import { PersonInterface } from './blabla';
...
export class SomeService {
person: PersonInterface;
}
So my question is - what is the purpose of using export in the declaration of the interface?
interface PersonInterface {
id: number;
name: string;
}
If I don't use export - I can still use it in the service and I even do not need to import it:
export class SomeService {
person: PersonInterface;
}
Everything works fine, no errors and from the IDE I can go to the declaration if the interface (Ctrl+Click over the interface name). Am I missing something?
Cheers
This goes to a long story of javascript history. In early ages you had to manually specify your javascript files using <script src="name.js"> tag with the exact order - top to bottom. After the script is attached all it's declarations like var a = 5 or function util(){} will be available for all the scripts below it and globally. It was very hard to hide this declarations from the global scope to achieve encapsulation, so there became a need to create something new.
Later on the es modules arrived. In order to use some function from other script, you had to export it at the very end of that script. That means that all the other, non-exported declarations (functions and variables), were encapsulated (hidden) from other scripts. This led to more resilient scripts with some defense from accident modifications (imagine someone uses a bunch of scripts for the first time, it would be a nightmare to analyze 10+ scripts without any docs). The script with export declaration looked like:
var a = 5;
function b(){};
module.exports = {
a: a,
b: b
}
In 2012s the Typescript was created. Besides all it's beautiful capabilities like static types, proper type-checking and syntax sugar, it also provided a better way to export/import functions, variables and classes. The syntax became:
import Something from '../other.script' for default exports
// other.script.ts contents
export default const A = '5'; // this will be imported in other file
import {exactOne, exactTwo} from '../other.script' for non-default exports
// other.script.ts contents
export const exactOne = 1;
export const exactTwo = 2;
export const exactThree = 3; // this is NOT imported above, but it's possible to import this const.
const exactFour = 4; // this const cannot be imported at all
import * as AllTogether from '../other.script' for bulk import.
// other.script.ts contents
export const a = 'a';
export const b = 'b';
// the AllTogether variable above will be imported like {a: 'a', b: 'b'}
Hope this helped!

Importing old javascript with namespace from ES6

I'm converting old javascript into ES6 using babel and webpack.
In multiple files I have something like
var BLOG = BLOG || {};
BLOG.myClass1 = ...
and in another file
var BLOG = BLOG || {};
BLOG.myClass2 = ...
So, I've added export {BLOG} to these files, but how can I import BLOG multiple times? It seems it is not allowed, while I'd like to do something like
import {BLOG} from 'file1.js'
import {BLOG} from 'file2.js'
and have myClass1 and myClass2 into BLOG.
Is there a way to do this?
So, I've added export {BLOG} to these files, but how can I import BLOG multiple times?
You'd have to use different import bindings for them:
import {BLOG as BLOG1} from 'file1.js';
import {BLOG as BLOG2} from 'file2.js';
...then use BLOG1 and BLOG2. Or if that bothers you, add
const BLOG = Object.assign({}, BLOG1, BLOG2);
after the imports and keep using BLOG.
If you have cyclic dependencies, it's possible that BLOG1 and BLOG2 may not be fully-populated right away. With true import/export, in that situation, the objects you receive will have their properties, but those properties won't be initialized yet. So with true import/export or a good simulation, you could use accessor properties to handle it:
// In a true ES2015+ module environment, or a simulated one that
// creates the properties up-front like the real one does
const BLOG = (() => {
const b = {};
for (const blog of [BLOG1, BLOG2]) {
for (const key of Object.keys(blog)) {
Object.defineProperty(b, key, {
get(name) {
return blog[name];
}
});
}
}
return b;
})();
(Obviously, you'd wrap that in a function and reuse it.)
In a simulated module environment that doesn't create the properties up-front like the real one would, you could use a proxy (though of course, if you're going to run this in a pre-ES2015 environment, it won't have Proxy):
const BLOGS = [BLOG1, BLOG2];
const BLOG = new Proxy({}, {
get(target, propName, receiver) {
const b = BLOGS.find(b => propName in b) || target;
return Reflect.get(b, propName, receiver);
}
});
Then, properties added to BLOG1 and BLOG2 after-the-fact still get resolved correctly.
All of which is an awful lot of bother just to avoid the search-and-replace mentioned next.
But: Instead of exporting BLOG, as SLaks says, export the classes, and import those. There's no need for a "namespace object" when you're using proper modules.
export { myClass1 };
and
export { myClass2 };
and then
import { myClass1 } from "file1.js";
import { myClass2 } from "file2.js";
You can even export the class as you define it, either:
export function myClass1() { /* ... */ }
or if using class notation:
export class myClass1 { /* ... */ }
Changing new BLOG.myClass1 to new MyClass1 across multiple files is a really simple search-and-replace. On *nix, you could throw sed at it and do an entire directory tree...
Side note: The overwhelming convention in JavaScript is that constructor functions (often loosely called "classes," e.g., functions you use with new) are written with an initial upper case character. E.g., MyClass1 and MyClass2.
You need to use import in the following manner
{BLOG as variable name} from file

Categories