Import, rename, and export a function in JavaScript? - javascript

With JavaScript what's the shortest way to import a named export, rename it, and export it again?
This code works but it feels more verbose than it should be
import { mock as myFunctionMock } from 'context/myFunction';
export const myFunction = myFunctionMock;

You can combine the import and export like so:
export { mock as myFunctionMock } from 'context/myFunction';
See MDN Docs
Note that you won't actually be able to use myFunctionMock within your code file since you haven't imported it. Neither mock nor myFunctionMock will be defined within this module.
This is a useful shorthand when you're building a library that will be used by other modules or by your end-user.
For example, if you had a utils library that you wanted to export, but you wanted to organize your util functions across several smaller files, such as stringUtils, objectUtils, dataUtils, etc, you can export the contents of those modules within your utils module to create a single, monolithic access point:
stringUtils.js
export function toLower(){}
export function toUpper(){}
objectUtils.js
export function propertyMap(){}
utils.js
export {
toLower as stringToLower,
toUpper as stringToUpper,
} from "stringUtils.js";
export {
propertyMap as objectPropertyMap
} from "objectUtils.js";
I wouldn't generally recommend this approach for internal code as it can make your dependency trees a bit wonky in some cases. It can, however, be extremely useful in situations where you want to import from a common interface but the implementation is dependent on the build (prod vs dev, web vs node, etc)

import { mock as myFunction } from 'context/myFunction';
export { myFunction };

in your original exporter, do:
module.exports = { mock: function () {...}}
When importing, do:
const myFunctionMock = require('file path of exporter');
then to reexport in the same file:
module.exports = {renamedMock: myFunctionMock};
Now any changes to mock will propagate to the other modules where it's referenced (side note, this is node.js in a nutshell).

Related

100% ESM module world - what it mean?

While reading about tree shaking in webpack documentation, I came across this sentence:
In a 100% ESM module world, identifying side effects is straightforward. However, we aren't there just yet.
What do they mean by "100% ESM module" and how it is different from the current import and export that we already use today?
reference: https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free
The documentation you're reading is contrasting two types of scripts:
Scripts which expose everything they do through what they import and export
Scripts which do something in addition to importing and exporting (this could be seen as a "side effect")
Consider a big library, one that installs itself as a namespace on the global object to expose its functionality. Let's say that jQuery did this - that is, that it runs something like
const jQuery = (function() {
// lots and lots of code
})();
export default jQuery;
window.jQuery = jQuery;
This contains a side-effect: the line
window.jQuery = jQuery;
This means that other parts of your application could use window.jQuery without jQuery being specifically imported into that module. For example, you might have
// someModule.js
export const doStuff = () => {
window.jQuery('div').text('Hi!');
};
And this can work without the line
import jQuery from 'jQuery';
inside the module script, because jQuery is on the window. (For this to work, there needs to be at least one module somewhere that does import 'jQuery'; or something like that, so that jQuery's code that assigns itself to the window runs)
Because of the side-effect, Webpack will have a harder time with automatic tree-shaking - you'll have to explicitly note which modules depend on modules with side-effects.
In contrast, a module without dependency side-effects would be the someModule.js example above: all it does it export a function, without adding or changing functionality elsewhere.
So by "100% ESM module", Webpack is probably referring to scripts for which all modules' dependencies are explicit with import statements, instead of having to depend on side-effects (like a non-imported module assigning something to the window).
There are two popular module syntax nodejs use.
Commonjs: https://nodejs.org/dist/latest-v14.x/docs/api/modules.html
// exporting
module.exports.a = 1
// or, exports is an alias to module.exports, for all differences check out docs
exports.a = 1
// you can assign module.exports object as well, this sets what's exported
module.exports = {
b: 2
}
// a is not exported anymore
// importing default import, imports module.exports object
const a = require('./b')
// or via named import
const {c} = require('./b');
ES modules: https://nodejs.org/dist/latest-v14.x/docs/api/esm.html
// names export
export const a = 1;
// default export
export default const b = 2;
// importing via name
import {a} from './c'
// importing default export
import c from './b'
Commonjs and esm are still in use. So we are not in %100 esm world yet.

Importing all exports in a module NodeJS

I want to be able to access all exports of a module without having to say module. before the export.
Let's say that I have a module:
// mymod.js
module.exports.foo = function() {
console.log("foo!");
}
module.exports.bar = "bar!";
And a main file:
// main.js
var mymod = require("./mymod.js");
mymod.foo();
Is there a way to call foo() without needing to say mymod. before? This can be achieved in python by saying import module as *.
What is the NodeJS equivalent to this?
In ES6 you can import modules in the following ways
import moduleName from "path/to/module"; // import default export from the file as moduleName object, moduleName can be anything
import { exportMemberName1, exportMemberName2, ... } from "path/to/module"; // destructured import, it will destructure import and can access the export module without prefixing anything
import * as moduleName from "path/to/module"; // import everything exported from the file as moduleName object, you can access every export members from that object, moduleName can be anything
These are the only methods provided by ES6 to import module (you can also use require).
If you have to import 100s of modules best ways is first method, import everything as an object and destructure on the go, I meant if you have lots of functions or methods, destructure what you want in that function in side that function, eg.
import * as moduleName from "path/to/file";
function function1(){
const { exportMember1, exportMember2 } = module;
}
function function2(){
const { exportMember1, exportMember5, exportMember7 } = module;
}
I want to be able to access all exports of a module without having to
say module. before the export.
Use the shorthand:
exports.myVar = myVar
exports.foo = () => {}
Or use an Object:
module.exports = {
foo,
myVar
}
// main.js
var mymod = require("./mymod.js");
mymod.foo();
Is there a way to call foo() without needing to say mymod. before?
This can be achieved in python by saying import module as *. What is
the NodeJS equivalent to this?
Use destructuring:
const { foo } = require("./mymod.js")
lets say that I have 100 exports in a file. Do I need to put commas
after every import inside the { }? There must be a better way to do
this
If you have 100 exports why would you want to import them all globally as their own functions? myMod.func is better for clarity.
A hacky workaround might be to do const myMod = require('myMod') then map it putting the functions on the global object. Or put them on the global from the start instead of exporting it.
You can use ES6 destructuring:
var { foo } = require("./mymod.js");
foo();
I have a situation where a I have a tiny-but-not-that-tiny generic utilities that is used along a couple of modules (all it's functions are used), in which there is a decent amount of modules already loaded. This functions are obviously named in a way you know there are a part of a generic utilities modules, so the "module.function" it's redundant, does not improve the readeability of the code. So, I prefered to mimick the "import * from module" of Python. Note that this is the first time I come across this situation, therefore, IMO, this mechanism, in almost every case, is not a good practice at all. The only way to do that, is iterating over the exports of the module, and adding the functions to the global object. I made a function to make the intention clear.
const importAll = () => {
return {
mod: null,
from(modName) {
this.mod = require(modName);
Object.keys(this.mod)
.forEach(exportedElementId => global[exportedElementId] = this.mod[exportedElementId]);
}
}
}
And it is used like this:
importAll().from('module-name');
Note that this only works if the module exports an object. Wont work if the module exports, for example, an array.
Here is another way, which may be a bit cleaner and more convenient in some cases: method importAll() is implemented inside export-heavy module, so it might be called immediately after require(), making this call very brief.
This works really well for large modules stuffed with simple standard functions and constants that are used across multiple projects.
Example:
// module.js
'use strict';
function func1() { return '4'; };
function func2() { return 2; };
function importAll() { delete this.importAll; Object.assign(global, this); };
module.exports = { func1, func2, importAll };
Then, in the main app, module can be unwrapped as follows:
// app.js
'use strict';
require('./module').importAll();
console.log("result: '%d'", func1() + func2());
There are few caveats though:
since properties/methods are added to global object, those might override some existing properties/methods, so be careful with naming.
those properties/methods will become available EVERYWHERE: in all modules, sub-modules, etc, so no need to call require() more than once.

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

How to call a public method of one JS module into another, using the Revealing Module Pattern?

I've been experimenting with Javascript's Revealing Module Pattern, but I don't quite understand if and how I can call a public method of one module into another. Suppose I have these two modules (code is simplified):
1) Module A
var lazyload = ( function() {
function loadDefault() {
$('.lazy').load();
}
return {
loadDefault: loadDefault
}
})();
2) Module B
var newposts = ( function() {
function addNewPosts() {
$('.posts').append();
}
});
How do I call the loadDefault() method from Module A into the addNewPosts() method from Module B? Not sure if this has anything to do with it, but maybe it's worth mentioning that I'm using Webpack, so in my main .js file I'm importing both modules as such:
import './ModuleA';
import './ModuleB';
How do I call the loadDefault() method from Module A into the addNewPosts() method from Module B?
If you were using the old-style revealing module pattern, you'd do lazyload.loadDefault(). But keep reading...
Not sure if this has anything to do with it, but maybe it's worth mentioning that I'm using Webpack, so in my main .js file I'm importing both modules as such:
import './ModuleA';
import './ModuleB';
Then you don't want to use the RMP. Instead, use export:
lazyload.js:
export function loadDefault() {
$('.lazy').load();
}
newposts.js:
import {loadDefault} from './ModuleA';
export function addNewPosts() {
loadDefault();
$('.posts').append();
}
Or if you want the one function you're exporting to be the default:
lazyload.js:
export default function loadDefault() {
$('.lazy').load();
}
...and then the import is
import loadDefault from './ModuleA';
The RMP was way to work around the problem of JavaScript not having modules. Once you're using actual modules (introduced in ES2015), you don't need the RMP (for modules) anymore.

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/"
};

Categories

Resources