Is `export Module from "module"` a valid JavaScript syntax? - javascript

Problem
In React Native project in my company I came across such code, aggregating exports from multiple modules:
export Icon from "./Icon";
export Input from "./Input";
export Pills from "./Pills";
My editor highlights this as invalid syntax. I checked MDN docs on export and indeed they don't list such a syntax for aggregation. From what they list it seems the proper one would be:
export { default as Icon } from "./Icon";
export { default as Input } from "./Input";
export { default as Pills } from "./Pills";
But then the first code works in React Native project I'm in.
Question
Is this a valid syntax in JavaScript, or is it only available by some third party package we're using in the project?

You are right, but you are not really using ES6 module.
You are using babel, with the metro-react-native-babel-preset. Which make the above syntax valid.
As always, there's a proposal to make it part of the language, but it's currently on stage one.
From the proposal:
The proposed addition follows this same symmetric pattern:
Importing the "default" name (existing):
import v from "mod";
Exporting that name (existing):
import v from "mod"; export {v};
Symmetric "export from" (proposed):
export v from "mod";

In the context of ES6 and Javascript. Syntactically react native method would be not valid. However As the #federkun suggested, it is valid under the context of babel and on the same desk proposal is already made.
However, "default" is used to export default exports which can be exported again
export {default} from '.\example.js'
or you can use name export within curly braces to export only named export. Besides, to export all the named export you can use "*"
export * from '.\example.js'
export {test} from '.\example.js'
Or you can add babel dependency to use the same syntax.

Related

Why does JavaScript have default exports?

Context
JavaScript has two types of exports: normal[1] and default.
EDIT: JavaScript has two types of export syntaxes
Normal exports
class Foo {...}
class Bar {...}
export {
Foo,
Bar,
};
or
export class Foo {...}
export class Bar {...}
Normal exports can be imported in two ways: namespace[1] imports and named imports (looks similar to destructuring).
Namespace imports
import * as Baz from './baz';
Named imports
import {Foo, Bar} from './baz';
Default exports
class Foo {...}
class Bar {...}
export default {
Foo,
Bar,
};
Default exports can also be imported in two ways: namespace imports and named imports (in a hackish way using destructuring in a separate statement)
Namespace imports
import Baz from './baz';
Named imports
import temp_Baz from './baz';
const {Foo, Bar} = temp_Baz;
Question
Both normal exports and default exports have the same functionality - they can be imported into a namespace, and they can be destructured into smaller pieces.
1) What are the reasons JavaScript has default exports, instead of sticking with just normal exports and having the import syntax be the following?
import <varName> from <location>;
<varName> would allow destructuring like any variable assignment, without a special "named" import.
Node.js managed without default exports, and the only additional change would be to allow exporting of a single value:
module.exports = class Foo {...}
This could be done with export = or export only or something similar:
export only class Foo {...}
So now you might ask, what is the difference between export only and export default?
export only exports could be imported with the same syntax, whereas export default requires a different importing syntax. To allow both syntaxes to work for the module user, the module must both export and export default the same items (which is something I do in all my modules).
export default is renamed to export only which is a better term in my opinion (less confusing; clearer)
2) All the differences listed above are pros. Are there any other differences that are cons? Or can any of the above differences also be cons?
Edit
It seems I misunderstood the intended use for export default.
It's for adding a default export on top of the regular exports.
So I'd now like to know when are default exports used? Although I probably shouldn't add more to this question.
If the only use for default exports is if your module only has a single item to export, then this question still applies.
Edit 2
Now it seems that the intended use is if a module only exports a single item. So my question still applies. Why not replace default exports with export only, removing the need for an additional default import syntax?
Notes
[1] I am not sure if this is the correct term to use
The existence of "default exports" as well as "named exports" is due to design by committee. This was convincingly argued by Andreas Rossberg during the original design discussions:
Some want modules in the conventional sense, as encapsulated namespaces with named exports, which you can import and access qualified or unqualified, and where imports are checked.
Some want modules in the specific pre-ES6 JavaScript style, where they can be any arbitrary JS value, and in the good old JavaScript tradition that checking doesn't matter.
The current design (including the newest suggestions for imports) seems to please neither side, because it tries to be the former semantically, but wants to optimise for the latter syntactically. The main outcome is confusion.
That is, the motivation for "default exports" was not technical, but political, designed to appease those in the CommonJS and AMD worlds, where a module exports a single value. This neatly explains why we have two module systems in one; something we don't see in other programming languages.
(Thanks a lot to Bergi, who found and cited this thread in his answer. However, I disagree with his conclusion that default exports are motivated by a need for a shorthand. I don't see much discussion of this in the original threads.)
JavaScript has two types of exports: normal and default.
No, not really. JavaScript has only one kind of export structure. It has different syntaxes though.
export default function x() {} is just a shorthand notation for function x(){}; export { x as default }.
import x from '…' is just a shorthand notation for import { default as x } from '…'.
The difference between your the two module exports you discussed is much bigger than the single default keyword. They only look so similar because you used shorthand notations. Fully spelled out, it's
export {
Foo as Foo,
Bar as Bar,
} // a declaration
vs
export default ({
Foo: Foo,
Bar: Bar,
}); // an object literal
Both normal exports and default exports have the same functionality - they can be imported into a namespace, and they can be destructured into smaller pieces.
No, they don't. Imports provide aliases for the exported variable declarations, there's no destructuring - and you cannot do that to properties of a default-exported object.
What are the reasons JavaScript has default exports, instead of sticking with just normal exports and having the import syntax be the following?
See https://esdiscuss.org/topic/moduleimport. The default-export syntax provides a shorthand syntax for exporting under the special name default (which is not a valid variable name otherwise), as it is a quite common use case to export only a single thing from a module. It doesn't require explicitly naming a value when there is only one in this module anyway. In this regard, it has very much the purpose you envisioned for your export only suggestion, but it is only one export not providing a full namespace of multiple aliasable exports.
export default {
Foo,
Bar,
}
I don't understand why you've demonstrated this structure. This isn't how it's supposed to be used.
The default export really be though of as just another export. If you import * as Package from "package" you'll realise... Package.default is the default export
The only change is the syntactic shortcut:
import alias from "package" = import {default as alias} from "package"
It makes consumption of many packages easier / simpler.
export = ... is not the same as export default ...
The prior returns a module structure of ... where as latter returns a module structure of {default: ...}

Override an export from another library es6

Given a javascript library (let's say supportlibrary) which has 100 named exports, I want to create my own compat-library which exports all named exports from supportlibrary but override a single named export with another.
For now, I can export all 99 named exports manually, but this would be a tedious job. I rather would have something like:
import {SupportComponent as ExcludedSupportComponent,...rest} from 'supportlibrary';
import SupportComponent from './MySupportComponent';
export {
...rest,
SupportComponent
}
Is something like this possible using es6 / tc39-stage-x functionality? or is this only possible with CommonJs?
You should be able to do
export * from 'supportlibrary';
export {default as SupportComponent} from './MySupportComponent';
to re-export all of the exports from 'supportlibrary', then export one additional named property that will take precedence over the export * version.

How to get around airbnb eslint import/prefer-default-export rule when using index.js for exports

For cases like this,
/ACollectionOfTinyComponent/index.js
import Container from './Container';
export {
Container,
};
So the index.js becomes a directory to include other small parts without having to write each Component Name out all the time.
So in this case, we can import a component in another component like following:
import {Container} from './ACollectionOfTinyComponent'
//then use Container in the code here
Is this a bad practice? Since if I have airbnb linter enable then I got error linting of
Prefer default export import/prefer-default-export
it asks me to add default but that will cause compile error
I found out that because I added only ONE import & export for the index.js. But if I add more than one its fine!
For example, if I do
import Container from './Container';
import Ezeewei from './Ezeewei';
export {
Container,
Ezeewei,
};
Note that I added one more import of Ezeewei.
Then the linting rule will pass!
it asks me to add default but that will cause compile error
You must be using the wrong syntax for exporting a default.
export { name1 as default, … };
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Syntax
import {Container} ... Is this a bad practice?
Yes. If you have a single entry point into a component (like a a class), you should export it as the default rather than a named export. The designers of the language gave default imports and exports a special syntax to promote it as the primary use case.
http://2ality.com/2014/09/es6-modules-final.html#default-exports-are-favored

Why do I need to wrap some importings with figure brackets {} in ES6? [duplicate]

This question already has answers here:
`export const` vs. `export default` in ES6
(6 answers)
Closed 6 years ago.
I found a strange situation in ES6. For example, I'm using npm packages react and react-router. I want to import them to the file:
import React from "react";
import { browserHistory } from "react-router";
The strange situation is that I need to wrap browserHistory in figure brackets, but I don't need to wrap React. What is the reason?
import { React } from "react"; // React is undefined
import browserHistory from "react-router"; // browserHistory is undefined
What's the reason that I need to customize my import?
ES6 modules differentiate between two kinds of exports: default exports and other exports.
Every module can have at most one default export. A default export is kind of like the “main attraction” of a module. It’s supposed to be the one thing that you probably meant the module to have. All other exports fit into the other category.
So a module can have any number of exports (even zero), of which at most one can be a default export.
On the export side of the syntax, a default export is simply marked by adding a default after the export keyword:
// this is a normal export
export var foo = 'foo';
// this is a default export
var bar = 'bar';
export default bar;
On the import side of the syntax, this gets a it more complicated: Default exports are imported outside of curly braces. All other exports are imported inside curly braces.
import bar, { foo } from 'some-module';
This would import the default exported member of the module as bar and also import the (named) other export foo. Note that default exports do not have a fixed name: The original name of the member at export time does not matter. Instead, you give it some name when importing it. So you could also write this instead:
import baz, { foo } from 'some-module';
This would still import the same default export from the module, but give it a different name. Other imports however are required to have the correct name, since that’s what’s used to identify them. You can however give them a different name by using the as keyword.
There are a few more things to know when using the export and import statements. You should check MDN for a full description of them.
If the module you are importing has a default export, then you do not have to use the { } syntax to access the given export. Named (non-default) exports must be accessed via the { } syntax. A module can have a default export as well as many named exports.
An example of that would be React which is a default export, but the module also has a named export of Component. To import both of these exports the syntax: import React, { Component } from 'react' would be used.

React. ES6. Babelify (w/ Browserify). Import alias fails [duplicate]

In version 5.6.4 of BabelJS, I seemingly cannot "import ... as." Here are examples of what I am trying to do:
In file 'test.js':
export default class Test {};
In file 'test2.js' (in the same directory):
import Test as Test2 from './test';
I have also tried to do:
import {Test as Test2} from './test';
Even though it says nothing about that here:
http://babeljs.io/docs/learn-es2015/#modules
And only uses brackets in the non-default syntax here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
Has anyone done this successfully?
EDIT: It is absolutely because of the default keyword. So, in this case, the question becomes, does anyone have any links to documentation that states that I should not be able to alias a default import? ECMA or Babel.
You can import the default export by either
import Test2 from './test';
or
import {default as Test2} from './test';
The default export doesn't have Test as a name that you would need to alias - you just need to import the default under the name that you want.
The best docs I've found so far is the article ECMAScript 6 modules: the final syntax in Axel Rauschmayers blog.

Categories

Resources