Exporting multiple constants as one json - javascript

I am having few constant files and an index.js file in a constant folder.
index.js file,
import * as env from "./env.constants";
import * as httpC from "./http.constants";
import * as localStorage from "./localStorage.constants";
import * as routes from "./routes.constants";
const appConstants = {
...env,
...httpC,
...localStorage,
...routes
};
console.log(appConstants);
export default appConstants;
and my constant files are as follows ,
http.constants.js
export const GET = "GET";
export const POST = "POST";
Other files are having same exports with different names.
The console output of index.js is a json, containing all the constants.
But when I am importing them as
import * as test from "./constants";
console.log(test);
I am getting the following output in my browser,
I want to use the constants in a single import,
import { GET, LOGIN_URL } from 'constants';
What have I missed ?

But when I am importing them as
import * as test from "./constants";
console.log(test);
I am getting the following output in my browser,
That's because you're importing the module's module namespace object (that's what import * does), and then outputting it directly.
To get the constants file you want, don't do the import * as and then combine them into an object and export that object as a default;instead, simply re-export them like this:
export * from "./env.constants";
export * from "./http.constants";
export * from "./localStorage.constants";
export * from "./routes.constants";
That will export all the named exports from all of those modules as named exports from the constants module.
What you were trying to do is a relatively common misunderstanding of the JavaScript module system, as compared to the CommonJS-like module system of Node.js. Named exports are not just properties on an object that's the default export. Named exports are their own first-level thing. If you do:
export default {
foo: 42
};
...you can't do import { foo } from "./mod" to import it, because foo isn't a named export, it's just a property on the default export, which is an object.
I am having few constant files and an index.js file in a constant folder.
...
import { GET, LOGIN_URL } from 'constants';
FWIW, relying on that to import a index.js file from the constants folder is relying on Node.js-specific features, not anything built into the JavaScript module system. If you only expect it to work in Node.js, that's fine, but just beware that it's not standard.

Related

How to make summary module that re-exports all the exports of sub-modules for ESM modules?

How do you re-export the exports from multiple files in an ESM module without listing each individual export separately?
I have a CommonJS module directory that consists of a number of files that I would like to convert to ESM imports/exports. Currently, I have an index.js file that contains this:
// this just re-exports everything that the sub-modules export
module.exports = [
'./mapConcurrent.js',
'./deferred.js',
'./utils.js',
'./rateMap.js',
'./concurrency.js',
'./retry.js',
].reduce((obj, file) => {
const m = require(file);
Object.assign(obj, m);
return obj;
}, {});
This re-exports all the exports of all the files in the module directory so that a client of this module can just import one file and get all the entry points for all the files without having to know which entry point is in which file and so on. This works fine for CommonJS.
How do you accomplish something similar in the ESM module world without having to explicitly name each export from all the sub-files?
You can use a star export for each of them:
export * from './mapConcurrent.js';
export * from './deferred.js';
export * from './utils.js';
export * from './rateMap.js';
export * from './concurrency.js';
export * from './retry.js';
It will re-export all the named exports from the respective module, but not the default export (those you'd need to rename or they would collide).
So no, you don't have to explicitly name each export, but you must explicitly declare all of the sub-files.

Exporting default from subdirectory [duplicate]

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

Confusion about functional equivalency of `export` usage

Shouldn't
import * as convict from "convict";
const config = convict({ ... });
// Perform validation
config.validate({ "allowed": "strict" });
export = config;
be functionally equivalent to:
import * as convict from "convict";
export const config = convict({ ... });
// Perform validation
config.validate({ "allowed": "strict" });
The first snippet works, but the second snippet introduces type errors such as:
TypeError: config.get is not a function
When imported using:
import * as config from "./config";
(This question and Frequent issue with TypeScript and preferring import over require are different. This question is about exports and what should be two equivalent usages. The other question is about imports.)
export const config = ... is so called "named export", it adds config variable to the list of names exported by the module. You can look at various variants of es6 export statement here, this particular one corresponds to the 4th line of the first example (note 'also var, const' comment):
export let name1 = …, name2 = …, …, nameN; // also var, const
and can be used with "named import* like
import {config} from '...';
export = config is entirely different, it's typescript-only export assignment. The documentation says that is should be imported as import config = require(...) which is again typescript-only special syntax.
With current version of TypeScript, export assignment can also be imported as
import * as config from 'module';
but there is breaking change in the works, in the future (maybe as soon as 2.8) this import will stop working with export assingment and will have to be written as
import config from 'module';
The two are indeed different. Essentially, it all has to do with the fact that in the second case config is a named export.
The first snippet produces an export that is just the config. If you did require("./config"), you'd get that config object. This is because you set the exports object to the config. That's why you have to do * as config when importing, because the entire imported object is what you're looking to get.
The second snippet produces an object with a named config field that points to your config; this is equivalent (ish) to doing:
exports = {
config: convict({ ... })
};
In this example, config is a named export. To import it, you'd have to get the config field of the exported object:
import { config } from "./config";

ES2015: Named import translation

I'm following ES2015. I want to translate regular javascript import statements to ES2015 import statement(s).
What I have:
I have javascript import line as below:
var db = require('../config').get('db')
What I've tried:
import { config } from '../config'
const db = config.db
NOTE
config folder has the index.js which I want to load. In the regular var ... = require('...') statement automatically loads index.js if exists. And I want the ES2015 script also automatically loads when imported.
I think what you're looking for is:
import { db } from '../config'
Assuming db is properly export-ed from config.js, that should work.
Just to clarify, there's three main kinds of imports in JS native modules:
Import the whole module:
import * as foo from 'path/to/foo';
const something = foo.something;
Import specific named exports of the module. This works if the module exports the appropriate objects using export statements:
import { something } from 'path/to/foo';
Import the default export of the module. This only works if the module has an export default statement in it:
import thedefaultexport from 'path/to/foo';
It looks like the '../config' module exports a single object with a get() method. If this is the case, import the whole module, like so:
import * as config from '../config';
And get the database like so:
const db = config.get('db');
If possible, you might want to refactor your '../config' module so that it exports db directly.
export {db};
And then you can use the syntax #AsadSaeeduddin suggested:
import {dp} from '../config';

Difference between import X and import * as X in node.js (ES6 / Babel)?

I have a node.js library lib written in ES6 (compiled with Babel) in which I export the following submodules:
"use strict";
import * as _config from './config';
import * as _db from './db';
import * as _storage from './storage';
export var config = _config;
export var db = _db;
export var storage = _storage;
If from my main project I include the library like this
import * as lib from 'lib';
console.log(lib);
I can see the proper output and it work as expected { config: ... }. However, if I try to include the library like this:
import lib from 'lib';
console.log(lib);
it will be undefined.
Can someone explain what is happening here? Aren't the two import methods supposed to be equivalent? If not, what difference am I missing?
import * as lib from 'lib';
is asking for an object with all of the named exports of 'lib'.
export var config = _config;
export var db = _db;
export var storage = _storage;
are named exports, which is why you end up with an object like you did.
import lib from 'lib';
is asking for the default export of lib.
e.g.
export default 4;
would make lib === 4. It does not fetch the named exports. To get an object from the default export, you'd have to explicitly do
export default {
config: _config,
db: _db,
storage: _storage
};
Just adding to Logan's solution because understanding import with brackets, * and without solved a problem for me.
import * as lib from 'lib';
is the equivalent of:
import {config, db, storage} as lib from 'lib';
Where the * is similar to a wildcard that imports all of the export var from lib.
export var config;
export var db;
export var storage;
Alternatively, using:
import lib from 'lib';
Allows you to only access the default export:
// lib.js
export default storage;
Using {} also only imports specific components from the module, which reduces the footprint with bundlers like Webpack.
While:
import storage, { config, db } from './lib'
would import all modules including export default storage;
See Dan Abramov's answer:
When should I use curly braces for ES6 import?
import X from Y; is a syntax sugar.
import lib from 'lib';
is equal to
import { default as lib } from 'lib';

Categories