Are You Using Imports & Exports Properly?
JavaScript Modules are separated by files and loaded asynchronously. Exports are defined using the export
keyword and imports are defined using import
keyword.
While the basics of imports and exports are simple to understand, there are many other ways to work with ES Modules. In this article, we’ll go over all of the ways in which you can export and import within your modules.
Exports
We’ll be looking into three types of exports:
1. Default Export
Every module has a single default export, which represents the main value that is exported from that module. You cannot have more than one default export in a module.
const foo = () => console.log('foo');export default foo;
We can also export a function declaration or a class declaration by default.
export default function foo() {
console.log('foo');
}
We can also export values as a default export.
export default 555;
2. Named Export
Any variable declaration can be exported when it is created, by adding export
keyword before its declaration. This basically creates a named export using the variable name as the export name.
export const foo = () => console.log('foo');
We can also immediately export function and class declarations.
export function foo() {
console.log('foo')
}
If we wanted to export a variable which was already defined, we could do that by wrapping the variable in curly brackets. This is usually done at the end of the file.
const foo = () => console.log('foo');export { foo };
In order to rename the named export, use the as
keyword. We can also export other variables at the same time.
const foo = () => console.log('foo');
const bar = 123;export { foo as printFoo, bar };
3. Aggregated Exports
There are cases where we’ll have to import modules from another file and export them. This scenario can be mostly found in places where you are importing modules from several files, and exporting all of them from one file. This can get tedious when you are importing and exporting lots of things at the same time. ES Modules allows us to import and export multiple values at the same time.
export * from "./foo.js";
This will take all of the named exports of ./foo.js
and re-export them. It won’t re-export default exports though, since a module can only have one default export. We can also specifically export default modules from other files, or name the default export when we re-export it.
export { default } from "./foo.js";// orexport { default as foo } from "./foo.js";
We can also selectively export different variables from another module, instead of re-exporting everything.
export { foo as printFoo, bar} from "./foo.js";
Finally, we can wrap up an entire module into a single named export using the as
keyword. Suppose, consider the following file.
// funcs.js
export function foo() {console.log('foo')}
export function bar() {console.log('bar')}
We can now pack this into a single export which is an object containing all of the named and default exports.
export * as funcs from "./funcs.js";
// { foo: function foo(), bar: function bar() }
Imports
We’ll be looking into three types of imports:
1. Default Imports
When we import a default value, we need to assign a name to it. Since it is the default, we can actually give it any name of your choice.
import fooFunctions from "./foo.js";
We can also import all of the exports, including named and default exports, at the same time. This will put all of them exports into an object, and the default export will be given the property name default
.
import * as foo from "./foo.js";
// { default: foo }
2. Named Imports
We can import any named export by wrapping the exported name in curly brackets.
import { foo, bar } from "./foo.js";
We can also rename the import as we import it using the as
keyword.
import {foo as fooFunction, bar} from './foo.js`
We can also mix named and default exports in the same import statement.
import foo, { bar } from "./foo.js";
Finally, we can import a module without listing any of the exports we want to use in our file. This is called a side-effect import, and will execute the code in the module without providing us any exported values.
import "./fruitBasket.js";
3. Dynamic Imports
Sometimes, we don’t know the name of a file before we import it or there isn’t a need to import a file until we are half-way through executing code. In those cases, we can use a dynamic import to import modules anywhere in our code.
Since ES Modules are asynchronous, the module won’t immediately be available. We have to wait for it to be loaded before we can do anything with it. If our module can’t be found, the dynamic import will throw an error.
It’s a good practice to use try
/ catch
when using dynamic imports.
async function printFn() {
try {
const fooFn = await import('./foo.js');
} catch {
console.error("Error getting foo module:");
}
return fooFn();
}
Conclusion
One thing to remember is that exports and static imports can only happen at the top level of the module. Dynamic imports, on the other hand, can be done from within a function.
I hope you found this article helpful. If so, get more similar content by subscribing to Decoded, our YouTube channel!