Node.js issues with exporting functions - javascript

I have a few questions about the nature of exporting functions in NodeJS:
Firstly this is an acceptable way to export a function:
exports.bread = function bread() {
return 'bread: 2';
};
However, it is not possible (maybe?) to export a function using this method:
function pullData(pair) {
console.log(pair);
}
module.exports = pullData;
The only problem with this second method is that the function is not hoisted and limits its' use elsewhere?
Another method for exporting variables is to include the variables within an object and export that object. However, in this case, the functions within the module have a limited scope...
So is there any easy way to export declarative functions and use them, or is doing so not something I should strive to achieve?
Screenshots from project:

When you write module.exports = something you are exporting only one thing. So your code should look like this
var pullData = require('./getTicker')
pullData('TEST')
If you want to write it the way you have done so then you need to export it differently, as only part of the module.exports object.
You can do this by writing
exports.pullData = pullData in your getTicker file.
Then you can import it and use it like you did:
var trackData = require('./getTicker')
trackData.pullData('TEST')

Try putting pullData in curly brackets:
module.exports = {pullData}
and when you require it, do this:
const {pullData} = require("./getTicker");
Hope it'll work.

Related

js import via building the string [duplicate]

Conditional
Is it possible to have conditional import statements like below?
if (foo === bar) {
import Baz from './Baz';
}
I have tried the above but get the following error (from Babel) when compiling.
'import' and 'export' may only appear at the top level
Dynamic
Is it possible to have dynamic import statements like below?
for (let foo in bar) {
if (bar.hasOwnProperty(foo)) {
import Baz from `./${foo}`;
}
}
The above receives the same error from Babel whilst compiling.
Is this possible to do or is there something I am missing?
Reasoning
The reason I am trying to do this is that I have a lot of imports for a number of "pages" and they follow a similar pattern. I would like to clean up my code base by importing these files with a dynamic for loop.
If this is not possible then is there a better way to handle large number of imports in ES6?
We do have dynamic imports proposal now with ECMA. This is in stage 2. This is also available as babel-preset.
Following is way to do conditional rendering as per your case.
if (foo === bar) {
import('./Baz')
.then((Baz) => {
console.log(Baz.Baz);
});
}
This basically returns a promise. Resolution of promise is expected to have the module. The proposal also has things like multiple dynamic imports, default imports, js file import etc. You can find more information about dynamic imports here.
You can't resolve dynamically your dependencies, as imports are meant for static analysis. However, you can probably use some require here, something like:
for (let foo in bar) {
if (bar.hasOwnProperty(foo)) {
const Baz = require(foo).Baz;
}
}
As this question is highly-ranked by Google, it is worth pointing out that things have changed since the older answers were posted.
MDN has this entry under 'Dynamic Imports':
The import keyword may be called as a function to dynamically import a
module. When used this way, it returns a promise.
import('/modules/my-module.js')
.then((module) => {
// Do something with the module.
});
This form also supports the await keyword.
let module = await import('/modules/my-module.js');
MDN also has a more detailed explanation.
A useful article on the subject can be found on Medium.
Since 2016 a lot has passed in JavaScript world, so I believe it's time to offer most updated info on this topic. Currently Dynamic imports are a reality both on Node and on browsers (natively if you don't care about IE, or with #babel/plugin-syntax-dynamic-import if you do care).
So, consider a sample module something.js with two named exports and one default export:
export const hi = (name) => console.log(`Hi, ${name}!`)
export const bye = (name) => console.log(`Bye, ${name}!`)
export default () => console.log('Hello World!')
We can use import() syntax to easily and cleanly load it conditionally:
if (somethingIsTrue) {
import('./something.js').then((module) => {
// Use the module the way you want, as:
module.hi('Erick') // Named export
module.bye('Erick') // Named export
module.default() // Default export
})
}
But since the return is a Promise, the async/await syntactic sugar is also possible:
async imAsyncFunction () {
if (somethingIsTrue) {
const module = await import('./something.js')
module.hi('Erick')
}
}
Now think about the possibilities along with Object Destructuring Assignment! For example, we are able to easily put only one of those named exports in memory for posterior use:
const { bye } = await import('./something.js')
bye('Erick')
Or maybe grab one of those named exports and rename it to anything else we want:
const { hi: hello } = await import('./something.js')
hello('Erick')
Or even rename the default exported function to something that makes more sense:
const { default: helloWorld } = await import('./something.js')
helloWorld()
Just a last (but no least) note: import() may looks like a function call, but it isn't a Function. It's a special syntax that just happens to use parentheses (similar to what happens with super()). So it's not possible to assign import to a variable or use things of the Function prototype, like call/apply.
Require will not solve your problem as it is a synchronous call. There are several options and they all involve
Asking for the module you need
Waiting for a promise to return the module
In ECMA Script there is support for lazy loading modules using SystemJS. This of course isn't supported in all browsers, so in the meantime you can use JSPM or a SystemJS shim.
https://github.com/ModuleLoader/es6-module-loader

How do you call a function inside a module.exports = function () in another class?

In the following example, simply putting module.exports = {save} on the jsFileName.js file functions is not an option here, due to limitations on my codebase. Is this possible to access the function from the export, inside of callFunctionFromAboveFile.js shown below? See the below example of how I'd like to access that function. I've searched all the other answers to questions similar but they all mention using the exports differently as I stated in my first line above.
If there is a way to access it as it is shown, please share your answer or details as to why it's not possible. Also, other ways to handle this would be helpful but I can't change the class up much given the limitation to the codebase.
jsFileName.js
module.exports = function (JsFileName) {
JsFileName.save = function (stuff) {}
}
callFunctionFromAboveFile.js
const JsFileName = require('jsFileName');
// TODO I'm not sure how this would call the save() w/out using exports differently.
// TODO I have to use exports as I've posted it in jsFileName.js
The default export of jsFileName.js is a function that adds functions to its parameter JsFileName.
Apparently, you can pass any object which is then modified to act as the module's exports.
That means: Pass any object you want to have the modules' functionality. Note that the object is not returned, so you have to keep the reference to it yourself.
// callFunctionFromAboveFile.js
const JsFileName = {};
require("jsFileName") // Get default export (the function)
(JsFileName); // Call with any object you want to "enhance"
JsFileName.save(/*...*/);

Calling an exported function by a string value of the function name

This is a very simple example of what I am trying to achieve, basically I want to call a function by a string value of it's name, e.g. "hello" should call hello()
I have a helper.js file which contains an exported function e.g.
export function hello() {
console.log('is it me you`re looking for?');
}
I am importing this into another js file for usage
import {hello} from './helper';
I have tried using eval, window and new Function to call my function but no luck
//getting console error "hello is not defined"
eval('hello()');
var fn = window['hello()'];
fn();
var fn = new Function('hello()');
fn();
If I wrap the function like so, the eval fires the wrapper.
function helloWrapper() {
hello();
}
eval('helloWrapper()');
I just cant seem to fire the exported hello() function directly. I have around 10 functions I'll need to fire so having a wrapper for each seems a bit hacky and wondering if there is a way I can achieve this?
Any help would be greatly appreciated if anyone can point me in the right direction.
Thanks in advance
eval("hello()") should work just fine -- but it's not how you should do this. :-)
Instead, build an object containing the functions:
import {hello} from './helper'; // In some environments, these need the
import {groot} from './groot'; // .js on the filenames.
// ...
const functions = {hello, groot/*, ... */};
and then call them like this:
functions[name]();
Live example on plnkr.co
Generally, referring functions by their names is unsafe in client-side code - or any other that can be minified. The approach explained in the question will work only because hello isn't just function name but an import. Due to how ES modules work, import names will be preserved on minification.
In order for a function to be referred by its name, it should be object property. In case of imports there's already such object, it's module export:
import * as helper from './helper';
helper['hello']();
In case there are multiple modules where functions may originate from, there should be intermediate module that re-exports them.
export * from './helper';
export * from './another-helper';
All functions from underlying modules will be available as properties when it's imported as *:
import * as helper from './reexported-helpers';
helper['hello']();
helper['bye']();

meaning of module.exports= function in node.js

I am taking first steps with node.js and obviously one of the first things i tried to do was exporting some data from a module, so i tried this simple case:
dummy.js:
var user = "rally";
module.exports = {
user:user
};
and than required it from a different file like this:
var dummy = require('./dummy.js');
console.log(dummy.user); // rally
So far so good, every thing works, but now i dived into code where there is this definition in the beginning of the module:
module.exports = function(passport,config, mongoose) {}
and i don't understand whats the meaning of it and how can i work with it.
just for trying to understand i defined some variables inside this abstract function but couldn't get their value from any other file.
any idea how can i export variables from module defined like this..? so for example i could require this module and get the "Dummy" variable and use it in a different file
module.exports = function(passport,config, mongoose) {
var dummy = "Dummy";
}
It works exactly the same as the first one does, only that it exports a function instead of an object.
The module that imports the module can then call that function:
var dummy = require('./dummy.js');
dummy();
any idea how can i export variables from module defined like this..?
Since functions are just objects, you can also assign properties to it:
module.exports = function(passport,config, mongoose) {}
module.exports.user = 'rally';
However I'd argue that this is less expected if a module directly exports a function. You are probably better off exporting the function as its own export:
exports.login = function(passport,config, mongoose) {}
exports.user = 'rally';
WHAT IS A MODULE?
A module encapsulates related code into a single unit of code. When creating a module, this can be interpreted as moving all related functions into a file.
// dummy.js
var exports = module.exports = {};
The utility of dummy.js increases when its encapsulated code can be utilized in other files. This is achieved by using exports.
HOW ARE THEY INVOKED?
You could declare your functions outside of the module.exports block. Functions inside exports can be invoked exactly the same way as variables or any other object.
EXAMPLE
//dummy.js
var myVariable = "foo";
var myFunction = function(){
//some logic
};
module.exports{
myVariable : myVariable,
myFunction : myFunction,
myVariableTypeTwo : "bar",
myFunctionTypeTwo : function () {
//some logic
}
}
We can now access the publicly available methods of dummy.js as a property from any js file.
var dummy = require('./dummy.js');
dummy.myVariable; //foo
dummy.myFunction();
dummy.myVariableTypeTwo; //bar
dummy.myFunctionTypeTwo();
NOTE
In the code above, we could have replaced module.exports with exports and achieved the same result. If this seems confusing, remember that exports and module.exports reference the same object.

Convert closure to es6 module

I'm using a javascript build environment that supports es6 modules (using es6-module-transpiler) so you can simply import stuff across different files.
Now I got a third party library that I'd like to be "importable".
The library populates its functionality like this:
(function () {/*...*/}).call(this);
Would it be safe to omit the closure and convert it to:
export default function () {/* ... */};
Or is there a better way?
Thanks in advance!
The original code you show invokes the anonymous function, which to make any sense must define a global variable, whereas the second code fragment you show merely exports the function, which is a different thing.
For purposes of discussion, let's assume the original code defines a global like this:
// my-third-party-module.js
(function() {
let myVar = 22;
window.MyThirdPartyModule = { log: function() { console.log(myVar); } };
}.call(this);
and you are using is as so:
// app.js
MyThirdPartyModule.log();
You could rewrite this as
// my-third-party-module.js
let myVar = 22;
export default { log: function() { console.log(myVar); } };
// app.js
import MyThirdPartyModule from `my-third-party-module';
MyThirdPartyModule.log();
Note that we have moved the variable myVar which was local to the anonymous function to the top module level.
However, depending on your preferences, rather than exporting a big object, which is sort of a pre-module mentality, you might want to export its APIs individually:
// my-third-party-module.js
let myVar = 22;
export function log { console.log(myVar); }
// app.js
import {log} from `my-third-party-module';
log();
or if you prefer
// app.js
import * as MyThirdPartyModule from `my-third-party-module';
MyThirdPartyModule.log();
However, all of these approaches assume you are able and willing to edit the source of the third party library. If that is not the case, you could write a little piece of glue code, such as
// my-third-party-module-interface.js
import 'my-third-party-module'; // This will run the module.
export default MyThirdPartyModule; // Export the global it defined.
// app.js
import MyThirdPartyModule from 'my-third-party-module-interface';
If you would prefer again to export individual APIs, you could extend the glue to re-export each of them:
// my-third-party-module-interface.js
import 'my-third-party-module'; // This will run the module.
const {log, otherAPI, ...} = MyThirdPartyModule;
export {log, otherAPI, ...};
// app.js
import {log} from 'my-third-party-module-interface';
The conversion of legacy dependencies is still an issue. And the horrible workflow they use makes things a lot harder, prefixing the actual code with browserify and webpack silliness.
So what to do? Existentially, the library is guaranteed only to deposit a global in window but by obscure and weird ways. And all slightly different.
So let the legacy simply do what it is supposed to do for you, but wrapped in a module so that you can import it rather than use a script tag:
https://medium.com/#backspaces/es6-modules-part-2-libs-wrap-em-up-8715e116d690

Categories

Resources