ES6 module syntax: is it possible to `export * as Name from ...`? - javascript

See question title. I found a great reference for the forms of export available, but I have not seen what I'm looking for.
Is it possible to do something like the following?
// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
export * as Constants from './constants.js';
I.e. this would provide a named export Constants inside of index.js containing all of the named exports from constants.js.
This answer seems to indicate it's not possible in TypeScript; is the same true for pure JavaScript?
(This example is a bit contrived; in reality I'm trying to have a prop-types.js module that uses named exports for internal use within the React package, but also exports the prop type definitions under PropTypes for external consumption. I tried to simplify for the sake of the question.)

No, it's not allowed in JS either, however there is a proposal to add it. For now, just use the two-step process with importing into a local variable and exporting that:
// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
import * as Constants from './constants.js';
export {Constants};

Today in 2019, it is now possible.
export * as name1 from …;

The proposal for this spec has merged to ecma262. If you're looking for this functionality in an environment that is running a previous JS, there's a babel plugin for it! After configuring the plugin (or if you're using ecma262 or later), you are able to run the JS in your question:
// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
export * as Constants from './constants.js';
// file: component.js
import { Constants } from './index.js';
const newVar = Constants.SomeConstant1; // 'yay'

// file: index.js
// note, this doesn't have to be at the top, you can put it wherever you prefer
import * as AllExportsFromThisModule from "./index.js"; // point this at the SAME file
export default AllExportsFromThisModule;
export const SOME_CONSTANT = 'yay';
export const SOME_OTHER_CONSTANT = 'yayayaya';

Related

Building CJS module from ESM with mixed named and default export - how to omit 'default'?

I am trying to configure rollup to build commonjs module from existing esm.
I have set of separate standalone methods, exported with default and available to import directly from package like:
import method1 from 'lib/method1'
And I have single entry point for all of them standalone.js to let user code import them separately using destructuring or at once as lib.
import _method1 from './method1'
import _method2 from './method2'
import _method3 from './method3'
export const method1 = _method1;
export const method2 = _method2;
export const method3 = _method3;
export default {method1,method2,method3};
So this is usage example:
import method1 from 'lib/method1'
//or
import { method1 } from 'lib/standalone'
//or
import standalone from 'lib/standalone'
//standalone.method1();
All this works fine for esm and I want similar experience for cjs.
Rollups do everything almost correct but it's complaining about mixed named/default export and adding extra module.exports.default field:
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var condense$1 = require('./condense.js');
var condenseDeep$1 = require('./condenseDeep.js');
var eachDeep$1 = require('./eachDeep.js');
// ...
var condense = condense$1;
var condenseDeep = condenseDeep$1;
var eachDeep = eachDeep$1;
//...
var standalone = {
condense: condense$1,
condenseDeep: condenseDeep$1,
eachDeep: eachDeep$1,
//...
};
exports.condense = condense;
exports.condenseDeep = condenseDeep;
exports.default = standalone; // <-- this one, how to remove it?
exports.eachDeep = eachDeep;
//...
so in commionjs usage looks like:
const method1 = require('lib/method1');
//or
const { method1 } = require ('lib/standalone');
//or
const standalone = require('lib/standalone');
//standalone.method1();
//standalone.default <--- this is redundant and confusing
I tried output.exports: 'named' rollup option - other entry points which are using default only also started having module.exports.default = .. instead of expected module.exports = ..
I tried output.exports: 'default' - it's not working with mixed default/named exports, throwing error.
A default export is a named export, it's just named default. ESM is built so that if you don't specify a name, it uses the export named default from the JS file.
Using CJS, there's no concept of default exports, everything is named.
The point is, nothing is wrong here. You can't mix named and default exports and use them without specifying .default in CJS.
Maybe this gist thread will help you out.
EDIT: You could always hack it as this answer suggests, but it is a hack, and then you'll lose named exports.

How do I correctly export and import a plain JS file into another JS file?

I need to export and import a plain js file to work keyboard navigation correctly.
I am following the example here,and using import and export pattern of ES5 but it is not linking one js file to another.
https://www.w3.org/TR/wai-aria-practices-1.1/examples/menubar/menubar-1/menubar-1.html#
This is my codepen.io link
https://codepen.io/ankita-sharma-the-flexboxer/project/editor/DzdmBE
module.exports = PopupMenu;
var myModule = require('./popuplinks');
There are multiple ways of exporting and importing JavaScript modules, in the past, we were using CommonJS modules which are in a format you've presented, they can be used in following way.
// module.js
const myModule = "something"
module.exports = myModule
// And then if you want to import in another file, you're using following sentence.
const module = require("./module")
Actually we're using ES6-like imports, you can read about them at MDN, I'm attaching a small sample of ES6+ export.
// module.js
const myModule = "Something"
export { myModule }
// And then
import {myModule} from './module'
Actually you should read post that will resolve your issue

ES6 Imports inside Export default

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

Importing external dependencies in Typescript

I am a newbie in typescript/node. I have a typescript file "order.ts" from which I would like to import an external config dependency from "config.ts"
My config file code is as below
let config = {
mongoAddress: "mongodb://localhost:27017/dts",
dataDirectory: "../../data/"
};
module.exports = config;
I am importing the config file in the order file as below
import { config } from "../../config";
However I am getting the TS compiler throwing error "... file not a module". Any clues how I should I be importing my external dependency in typescript
The main part here is you want to export your object instance. You're on the right track with that, but there may be an easier way for you.
In this case something like wrapping it in a class and exporting that:
export class Config {
mongoAddress = 'mongodb://localhost:27017/dts';
dataDirectory = '../../data/';
}
Notice the export before class. The same can be applied to interfaces, enums etc. By exporting it this way you can then import it and initialise it:
import { Config } from '../config';
var c = new Config();
console.log(c.mongoAddress);
This will not make it a variable, like in your original example, but you'll simply wrap it in a class. This is also why you have to initialise it first using new Config().
Now, I'm assuming you want these properties simply to be accessed globally. And perhaps even static/readonly, so you don't have to initialise the class each time. Making use of the static typing of TypeScript, the sample would in this case be better refactored to something like this:
export class Config {
public static readonly mongoAddress: string = 'mongodb://localhost:27017/dts';
public static readonly dataDirectory: string = '../../data/';
}
With this, calling it is even less obtrusive - and very type safe:
console.log(Config.mongoAddress);
console.log(Config.dataDirectory);
Now exporting this way is just one of the options. It actually depends entirely on the library structure you're using throughout your application (or from third partie libraries, for that matter). It's a bit of dry reading, but I recommend you have a look at the different structures to get acquainted with terms like UMD and modules and how they relate to an import.
Hope this helps!
There are 2 ways you can do import and export.
1) default export
// config.ts
export const config = {
mongoAddress: "mongodb://localhost:27017/dts",
dataDirectory: "../../data/"
};
export default config;
// your other file
import configs from './config';
Note: Here you can give any name for the imported module;
2) normal export with exact declaration name while importing.
// config.ts
export const config = {
mongoAddress: "mongodb://localhost:27017/dts",
dataDirectory: "../../data/"
};
// your other file
import { config } from './config';
Note: Here you have to give the exact name of the module that you exported.
Best practices to follow while exporting configs.
create a static class with static variables in the code. Which likely means that these configs are fixed stuffs.
module.exports is the node syntax for exporting modules. Typescript has a keyword names export so you can just use this:
export const config = {
mongoAddress: "mongodb://localhost:27017/dts",
dataDirectory: "../../data/"
};

How to import everything exported from a file with ES2015 syntax? Is there a wildcard?

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;

Categories

Resources