How to import sub objects - javascript

Given these exports in a plugin
// Imagine these inner functions are written somewhere
export const WindowFunctions={
maximize: maximizeFunction,
minimize: minimizeFunction
}
export const FileFunctions={
open: openFileFunction,
close: closeFileFunction
}
// Pretend there is 20 other exports here
export default{
WindowFunctions,
FileFunctions,
// imagine those 20 other exports here too
}
When using require, you could access them with
const {maximize} = require('yourPlugin').WindowFunctions
How can this be achieved with import instead?
So far I have been doing this
import {WindowFunctions} from 'yourPlugin'
const maximize = WindowFunctions.maximize
Is there a nicer way to import these?
Thanks

import {WindowFunctions: {maximize}} from 'yourPlugin'
ES2015 named imports do not destructure. Use another statement for destructuring after the import.

Related

Calling a function from a class to another generate an error in Next.js [duplicate]

I am trying to determine if there are any big differences between these two, other than being able to import with export default by just doing:
import myItem from 'myItem';
And using export const I can do:
import { myItem } from 'myItem';
Are there any differences and/or use cases other than this?
It's a named export vs a default export. export const is a named export that exports a const declaration or declarations.
To emphasize: what matters here is the export keyword as const is used to declare a const declaration or declarations. export may also be applied to other declarations such as class or function declarations.
Default Export (export default)
You can have one default export per file. When you import you have to specify a name and import like so:
import MyDefaultExport from "./MyFileWithADefaultExport";
You can give this any name you like.
Named Export (export)
With named exports, you can have multiple named exports per file. Then import the specific exports you want surrounded in braces:
// ex. importing multiple exports:
import { MyClass, MyOtherClass } from "./MyClass";
// ex. giving a named import a different name by using "as":
import { MyClass2 as MyClass2Alias } from "./MyClass2";
// use MyClass, MyOtherClass, and MyClass2Alias here
Or it's possible to use a default along with named imports in the same statement:
import MyDefaultExport, { MyClass, MyOtherClass} from "./MyClass";
Namespace Import
It's also possible to import everything from the file on an object:
import * as MyClasses from "./MyClass";
// use MyClasses.MyClass, MyClasses.MyOtherClass and MyClasses.default here
Notes
The syntax favours default exports as slightly more concise because their use case is more common (See the discussion here).
A default export is actually a named export with the name default so you are able to import it with a named import:
import { default as MyDefaultExport } from "./MyFileWithADefaultExport";
export default affects the syntax when importing the exported "thing", when allowing to import, whatever has been exported, by choosing the name in the import itself, no matter what was the name when it was exported, simply because it's marked as the "default".
A useful use case, which I like (and use), is allowing to export an anonymous function without explicitly having to name it, and only when that function is imported, it must be given a name:
Example:
Export 2 functions, one is default:
export function divide( x ){
return x / 2;
}
// only one 'default' function may be exported and the rest (above) must be named
export default function( x ){ // <---- declared as a default function
return x * x;
}
Import the above functions. Making up a name for the default one:
// The default function should be the first to import (and named whatever)
import square, {divide} from './module_1.js'; // I named the default "square"
console.log( square(2), divide(2) ); // 4, 1
When the {} syntax is used to import a function (or variable) it means that whatever is imported was already named when exported, so one must import it by the exact same name, or else the import wouldn't work.
Erroneous Examples:
The default function must be first to import
import {divide}, square from './module_1.js
divide_1 was not exported in module_1.js, thus nothing will be imported
import {divide_1} from './module_1.js
square was not exported in module_1.js, because {} tells the engine to explicitly search for named exports only.
import {square} from './module_1.js
More important difference is: export default exports value, while export const/export var/export let exports reference(or been called live binding). Try below code in nodejs(using version 13 or above to enable es module by default):
// a.mjs
export let x = 5;
// or
// let x = 5;
// export { x }
setInterval(() => {
x++;
}, 1000);
export default x;
// index.mjs
import y, { x } from './1.mjs';
setInterval(() => {
console.log(y, x);
}, 1000);
# install node 13 or above
node ./index.mjs
And we should get below output:
6 5
7 5
8 5
...
...
Why we need this difference
Most probably, export default is used for compatibility of commonjs module.exports.
How to achieve this with bundler(rollup, webpack)
For above code, we use rollup to bundle.
rollup ./index.mjs --dir build
And the build output:
// build/index.js
let x = 5;
// or
// let x = 5;
// export { x }
setInterval(() => {
x++;
}, 1000);
var y = x;
setInterval(() => {
console.log(y, x);
}, 1000);
Please pay attention to var y = x statement, which is the default.
webpack has similar build output. When large scale of modules are added to build, concatenateing text is not sustainable, and bundlers will use Object.defineProperty to achieve binding(or called harmony exports in webpack). Please find detail in below code:
main.js
...
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
...
// 1.js
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[1],[
/* 0 */,
/* 1 */
/***/ (function(__webpack_module__, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "x", function() { return x; });
let x = 5;
// or
// let x = 5;
// export { x }
setInterval(() => {
x++;
}, 1000);
/* harmony default export */ __webpack_exports__["default"] = (x);
/***/ })
]]);
Please find the difference behavior between /* harmony export (binding) */ and /* harmony default export */.
ES Module native implementation
es-modules-a-cartoon-deep-dive by Mozilla told why, what and how about es module.
Minor note: Please consider that when you import from a default export, the naming is completely independent. This actually has an impact on refactorings.
Let's say you have a class Foo like this with a corresponding import:
export default class Foo { }
// The name 'Foo' could be anything, since it's just an
// Identifier for the default export
import Foo from './Foo'
Now if you refactor your Foo class to be Bar and also rename the file, most IDEs will NOT touch your import. So you will end up with this:
export default class Bar { }
// The name 'Foo' could be anything, since it's just an
// Identifier for the default export.
import Foo from './Bar'
Especially in TypeScript, I really appreciate named exports and the more reliable refactoring. The difference is just the lack of the default keyword and the curly braces. This btw also prevents you from making a typo in your import since you have type checking now.
export class Foo { }
//'Foo' needs to be the class name. The import will be refactored
//in case of a rename!
import { Foo } from './Foo'
From the documentation:
Named exports are useful to export several values. During the import, one will be able to use the same name to refer to the corresponding value.
Concerning the default export, there is only a single default export per module. A default export can be a function, a class, an object or anything else. This value is to be considered as the "main" exported value since it will be the simplest to import.
When you put default, its called default export. You can only have one default export per file and you can import it in another file with any name you want. When you don't put default, its called named export, you have to import it in another file using the same name with curly braces inside it.

Export all constants from files into index.ts and then export those constants as keys of an object?

I have a constant library that has many files such as the following structure:
#1 index.ts
#2 src/
contact.ts
const first = [];
const second = [];
const third = [];
location.ts
const first = '';
const second = '';
const third = '';
Is it possible to import and export all of the constants from each file into index.ts such that I can import into a project such as the following:
// Imports: Constants
import { constants } from '#jeff/constants-library';
console.log(constants.contact.first);
console.log(constants.contact.second);
console.log(constants.contact.third);
What is the fastest/most efficient way to dynamically export the constants from my library files so I can import the into my projects?
In your files like contact and location, you'll need to mark the const values you want as exports. Modules are designed for encapsulation, so dynamic export isn't really an option here. However, it's just a matter of adding the keyword export:
export const first = [];
After that, you can create a constants-library.ts or constants-library/index.ts which automatically exports and imports:
import * as foo from './foo';
import * as bar from './bar';
export const constants = { foo, bar };
At this point, assuming your #jeff path is set up, your code should work as expected:
import { constants } from '#jeff/constants-library';
console.log(constants.contact.first);
Note that this will include all of the exports in your files, since TypeScript can't tell which constants you want or didn't want--it only knows which exports you've listed. As an alternative, rather than exporting all of your consts individually, you could bundle them into a single export using object shorthand.
// in contact.ts and location.ts
export constants = { first, second, third };
// in constant-library.ts or constant-library/index.ts
import { constants as contact } from './contact';
import { constants as location } from './location';
export constants = { contact, location };

Import all files in a directory at once [duplicate]

With ES6, I can import several exports from a file like this:
import {ThingA, ThingB, ThingC} from 'lib/things';
However, I like the organization of having one module per file. I end up with imports like this:
import ThingA from 'lib/things/ThingA';
import ThingB from 'lib/things/ThingB';
import ThingC from 'lib/things/ThingC';
I would love to be able to do this:
import {ThingA, ThingB, ThingC} from 'lib/things/*';
or something similar, with the understood convention that each file contains one default export, and each module is named the same as its file.
Is this possible?
I don't think this is possible, but afaik the resolution of module names is up to module loaders so there might a loader implementation that does support this.
Until then, you could use an intermediate "module file" at lib/things/index.js that just contains
export * from 'ThingA';
export * from 'ThingB';
export * from 'ThingC';
and it would allow you to do
import {ThingA, ThingB, ThingC} from 'lib/things';
Just a variation on the theme already provided in the answer, but how about this:
In a Thing,
export default function ThingA () {}
In things/index.js,
export {default as ThingA} from './ThingA'
export {default as ThingB} from './ThingB'
export {default as ThingC} from './ThingC'
Then to consume all the things elsewhere,
import * as things from './things'
things.ThingA()
Or to consume just some of things,
import {ThingA,ThingB} from './things'
The current answers suggest a workaround but it's bugged me why this doesn't exist, so I've created a babel plugin which does this.
Install it using:
npm i --save-dev babel-plugin-wildcard
then add it to your .babelrc with:
{
"plugins": ["wildcard"]
}
see the repo for detailed install info
This allows you to do this:
import * as Things from './lib/things';
// Do whatever you want with these :D
Things.ThingA;
Things.ThingB;
Things.ThingC;
again, the repo contains further information on what exactly it does, but doing it this way avoids creating index.js files and also happens at compile-time to avoid doing readdirs at runtime.
Also with a newer version you can do exactly like your example:
import { ThingsA, ThingsB, ThingsC } from './lib/things/*';
works the same as the above.
You now can use async import():
import fs = require('fs');
and then:
fs.readdir('./someDir', (err, files) => {
files.forEach(file => {
const module = import('./' + file).then(m =>
m.callSomeMethod();
);
// or const module = await import('file')
});
});
Great gugly muglys! This was harder than it needed to be.
Export one flat default
This is a great opportunity to use spread (... in { ...Matters, ...Contacts } below:
// imports/collections/Matters.js
export default { // default export
hello: 'World',
something: 'important',
};
// imports/collections/Contacts.js
export default { // default export
hello: 'Moon',
email: 'hello#example.com',
};
// imports/collections/index.js
import Matters from './Matters'; // import default export as var 'Matters'
import Contacts from './Contacts';
export default { // default export
...Matters, // spread Matters, overwriting previous properties
...Contacts, // spread Contacts, overwriting previosu properties
};
// imports/test.js
import collections from './collections'; // import default export as 'collections'
console.log(collections);
Then, to run babel compiled code from the command line (from project root /):
$ npm install --save-dev #babel/core #babel/cli #babel/preset-env #babel/node
(trimmed)
$ npx babel-node --presets #babel/preset-env imports/test.js
{ hello: 'Moon',
something: 'important',
email: 'hello#example.com' }
Export one tree-like default
If you'd prefer to not overwrite properties, change:
// imports/collections/index.js
import Matters from './Matters'; // import default as 'Matters'
import Contacts from './Contacts';
export default { // export default
Matters,
Contacts,
};
And the output will be:
$ npx babel-node --presets #babel/preset-env imports/test.js
{ Matters: { hello: 'World', something: 'important' },
Contacts: { hello: 'Moon', email: 'hello#example.com' } }
Export multiple named exports w/ no default
If you're dedicated to DRY, the syntax on the imports changes as well:
// imports/collections/index.js
// export default as named export 'Matters'
export { default as Matters } from './Matters';
export { default as Contacts } from './Contacts';
This creates 2 named exports w/ no default export. Then change:
// imports/test.js
import { Matters, Contacts } from './collections';
console.log(Matters, Contacts);
And the output:
$ npx babel-node --presets #babel/preset-env imports/test.js
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello#example.com' }
Import all named exports
// imports/collections/index.js
// export default as named export 'Matters'
export { default as Matters } from './Matters';
export { default as Contacts } from './Contacts';
// imports/test.js
// Import all named exports as 'collections'
import * as collections from './collections';
console.log(collections); // interesting output
console.log(collections.Matters, collections.Contacts);
Notice the destructuring import { Matters, Contacts } from './collections'; in the previous example.
$ npx babel-node --presets #babel/preset-env imports/test.js
{ Matters: [Getter], Contacts: [Getter] }
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello#example.com' }
In practice
Given these source files:
/myLib/thingA.js
/myLib/thingB.js
/myLib/thingC.js
Creating a /myLib/index.js to bundle up all the files defeats the purpose of import/export. It would be easier to make everything global in the first place, than to make everything global via import/export via index.js "wrapper files".
If you want a particular file, import thingA from './myLib/thingA'; in your own projects.
Creating a "wrapper file" with exports for the module only makes sense if you're packaging for npm or on a multi-year multi-team project.
Made it this far? See the docs for more details.
Also, yay for Stackoverflow finally supporting three `s as code fence markup.
Similar to the accepted answer but it allows you to scale without the need of adding a new module to the index file each time you create one:
./modules/moduleA.js
export const example = 'example';
export const anotherExample = 'anotherExample';
./modules/index.js
// require all modules on the path and with the pattern defined
const req = require.context('./', true, /.js$/);
const modules = req.keys().map(req);
// export all modules
module.exports = modules;
./example.js
import { example, anotherExample } from './modules'
If you are using webpack. This imports files automatically and exports as api namespace.
So no need to update on every file addition.
import camelCase from "lodash-es";
const requireModule = require.context("./", false, /\.js$/); //
const api = {};
requireModule.keys().forEach(fileName => {
if (fileName === "./index.js") return;
const moduleName = camelCase(fileName.replace(/(\.\/|\.js)/g, ""));
api[moduleName] = {
...requireModule(fileName).default
};
});
export default api;
For Typescript users;
import { camelCase } from "lodash-es"
const requireModule = require.context("./folderName", false, /\.ts$/)
interface LooseObject {
[key: string]: any
}
const api: LooseObject = {}
requireModule.keys().forEach(fileName => {
if (fileName === "./index.ts") return
const moduleName = camelCase(fileName.replace(/(\.\/|\.ts)/g, ""))
api[moduleName] = {
...requireModule(fileName).default,
}
})
export default api
I've used them a few times (in particular for building massive objects splitting the data over many files (e.g. AST nodes)), in order to build them I made a tiny script (which I've just added to npm so everyone else can use it).
Usage (currently you'll need to use babel to use the export file):
$ npm install -g folder-module
$ folder-module my-cool-module/
Generates a file containing:
export {default as foo} from "./module/foo.js"
export {default as default} from "./module/default.js"
export {default as bar} from "./module/bar.js"
...etc
Then you can just consume the file:
import * as myCoolModule from "my-cool-module.js"
myCoolModule.foo()
Just an other approach to #Bergi's answer
// lib/things/index.js
import ThingA from './ThingA';
import ThingB from './ThingB';
import ThingC from './ThingC';
export default {
ThingA,
ThingB,
ThingC
}
Uses
import {ThingA, ThingB, ThingC} from './lib/things';
Nodejs ? Do like this:
Create a folder with index.js, in index file, add this:
var GET = require('./GET');
var IS = require('./IS');
var PARSE = require('./PARSE');
module.exports = { ...GET, ...IS, ...PARSE};
And, in file GET.js, or IS.js export as normal:
module.exports = { /* something as you like */}
ANd now, you need only including index.js like:
const Helper = require('./YourFolder');
Helper will include all of function in YourFolder.
Good day!
This is not exactly what you asked for but, with this method I can Iterate throught componentsList in my other files and use function such as componentsList.map(...) which I find pretty usefull !
import StepOne from './StepOne';
import StepTwo from './StepTwo';
import StepThree from './StepThree';
import StepFour from './StepFour';
import StepFive from './StepFive';
import StepSix from './StepSix';
import StepSeven from './StepSeven';
import StepEight from './StepEight';
const componentsList= () => [
{ component: StepOne(), key: 'step1' },
{ component: StepTwo(), key: 'step2' },
{ component: StepThree(), key: 'step3' },
{ component: StepFour(), key: 'step4' },
{ component: StepFive(), key: 'step5' },
{ component: StepSix(), key: 'step6' },
{ component: StepSeven(), key: 'step7' },
{ component: StepEight(), key: 'step8' }
];
export default componentsList;
You can use require as well:
const moduleHolder = []
function loadModules(path) {
let stat = fs.lstatSync(path)
if (stat.isDirectory()) {
// we have a directory: do a tree walk
const files = fs.readdirSync(path)
let f,
l = files.length
for (var i = 0; i < l; i++) {
f = pathModule.join(path, files[i])
loadModules(f)
}
} else {
// we have a file: load it
var controller = require(path)
moduleHolder.push(controller)
}
}
Then use your moduleHolder with dynamically loaded controllers:
loadModules(DIR)
for (const controller of moduleHolder) {
controller(app, db)
}
I was able to take from user atilkan's approach and modify it a bit:
For Typescript users;
require.context('#/folder/with/modules', false, /\.ts$/).keys().forEach((fileName => {
import('#/folder/with/modules' + fileName).then((mod) => {
(window as any)[fileName] = mod[fileName];
const module = new (window as any)[fileName]();
// use module
});
}));
if you don't export default in A, B, C but just export {} then it's possible to do so
// things/A.js
export function A() {}
// things/B.js
export function B() {}
// things/C.js
export function C() {}
// foo.js
import * as Foo from ./thing
Foo.A()
Foo.B()
Foo.C()

How to import submodules and alias them to a variable in ES6

I want to create a module with some modules of a js file and do something like this:
import { CONSTANT01, CONSTANT02 } as selectedConstants from './constants'
console.log(selectedConstants) // output => {CONSTANT01: 'CONSTANT01', CONSTANT02: 'CONSTANT02'}
Can this functionality be done?
No, it can't be done like this. Just use a namespace import:
import * as selectedConstants from './constants';
console.log(selectedConstants.CONSTANT01) // output => 'CONSTANT01'
console.log(selectedConstants.CONSTANT02) // output => 'CONSTANT02'

How to import a static member of a class?

I am trying to import a static member of a class into a file by just using standard import syntax. To give context:
Destructuring works on the static method of a class:
class Person {
static walk() {
console.log('Walking');
}
}
let {walk} = Person;
console.log(walk); // walk function
However, I thought imports behaved like destructuring assignments. If that's true, then I would expect the following to work. But, when I attempt to import the walk method, it just comes back as undefined:
Destructuring through imports, why doesn't it work?
person.js
export default class Person {
static walk() {
console.log('Walking');
}
}
walker.js
import {walk} from './person';
console.log(walk); // undefined
Since this doesn't seem to work, how can I import a static method from a class to another module?
export default can be mixed with normal exports in ES6. For example :
// module-a.js
export default a = 1;
export const b = 2;
// module-b.js
import a, { b } from "./module-a";
a === 1;
b === 2;
This means that the import brackets are not the same as a destructor assignment.
What you want to achieve is actually not possible in the ES6 specs. Best way to do it, would be to use the destructuring after your import
import Person from "./person";
const { walk } = Person;
The syntax you are using is actually a named import, not a destructuring assignment, although they look similar. There is no destructuring import in ES6. All you can do is to add a destructuring assignment to the next line, but keep in mind that this will break when the imports are cyclic.
import Person from './person';
const { walk } = Person;
console.log(walk);

Categories