To break it down and simplify it a bit: Imagine I have three files in my project. One main.js, and two modules: moduleA.js and moduleB.js.
main.js accesses moduleA.js which calls a function from moduleB.js. Now moduleB.js finds out that it needs an information that is only available in moduleA.js. Of course moduleB.js tries to access a function in moduleA.js which is technically able to give this information to moduleB.js but there is an error.
Here is the simplified code.
main.js
var a = require("./moduleA.js");
console.log(a.respond());
moduleA.js
var b = require("./moduleB.js");
module.exports = {
respond: function(){
return b.returnAnswerForModuleA();
},
getSomeInformationOnlyAvailableInA: function(){
return "This is the information we need!";
}
};
moduleB.js
var a = require("./moduleA.js");
module.exports = {
returnAnswerForModuleA: function(){
return a.getSomeInformationOnlyAvailableInA()
}
};
Here is the error message:
/Users/Tim/Code/ChatBot/test/moduleB.js:5
return a.getSomeInformationOnlyAvailableInA()
^
TypeError: a.getSomeInformationOnlyAvailableInA is not a function
at Object.module.exports.returnAnswerForModuleA (/Users/Tim/Code/ChatBot/test/moduleB.js:5:16)
at Object.module.exports.respond (/Users/Tim/Code/ChatBot/test/moduleA.js:5:18)
at Object.<anonymous> (/Users/Tim/Code/ChatBot/test/main.js:3:15)
at Module._compile (module.js:425:26)
at Object.Module._extensions..js (module.js:432:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:311:12)
at Function.Module.runMain (module.js:457:10)
at startup (node.js:136:18)
at node.js:972:3
Why cannot I access moduleA.js from moduleB.js?
To restructure my code is not really an option!
Thanks for help!
This looks like an issue with circular dependencies in node.js where a circular dependency causes one module to be resolved as an empty object (thus causing the error you see). See these articles which explain:
Node.js and circular dependencies
Circular dependencies in Node.js
The first article offers two possible solutions: "delaying invocation of dependency until runtime" and "replace circular dependency with dependency injection".
I think you can work around the circular issue by changing module B to this:
var moduleA;
module.exports = {
returnAnswerForModuleA: function(){
if (!moduleA) {
moduleA = require("./moduleA.js");
}
return moduleA.getSomeInformationOnlyAvailableInA()
}
};
This delays the loading of module A in module B until runtime by which time, it is already successfully loaded and in the module cache, thus avoiding the circular dependency.
Related
so I'm trying to call the function jsonToAim(), which is created in a.js, in another script b.js
this is how I defined it in a.js:
export function jsonToAim(jsonObj){...}
this is how I called it in b.js
const backend = require('./a')`
let aimObj = backend.jsonToAim(jsonObj);
I ended up getting this error:
export function jsonToAim(jsonObj){
^^^^^^
SyntaxError: Unexpected token 'export'
at wrapSafe (internal/modules/cjs/loader.js:992:16)
at Module._compile (internal/modules/cjs/loader.js:1040:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1097:10)
at Module.load (internal/modules/cjs/loader.js:941:32)
at Function.Module._load (internal/modules/cjs/loader.js:782:14)
at Module.require (internal/modules/cjs/loader.js:965:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.<anonymous> (/create-aims/getAim.js:4:17)
at Module._compile (internal/modules/cjs/loader.js:1076:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1097:10)
does anyone know where I went wrong? sorry if this is a stupid question i'm super new to js
There are multiple ways to export stuff in JS... e.g., the CommonsJS vs ES6 export syntax.
NodeJS for whatever reason doesn't support at this time the ES6 import/export syntax you're employing.
Try the CommonJS syntax (require/exports):
const jsonToAim = (jsonObj) => {...}
//At the end of your file:
export {
jsonToAim
}
Here's a really good thread about the ES6 vs CommonJS export syntax.
The problem is that you use ES Modules instead of CommonJS
Node.js uses by default Common js require()
That means that:
export function jsonToAim(jsonObj){...}
should be
function jsonToAim(jsonObj){...}
module.exports.jsonToAim = jsonToAim;
Later you import it with:
const { jsonToAim } = require(...);
However you can use ES modules in node.js too.
I have written an similar answer for this type of problem:
ES6 imports for JWT
Hello and thank you in advance.
This may be a rather simple scenario, however, I am new to Nodejs.
I have a main script which I am calling from javascript using IISNode. Everything has worked great until I decided to rename a dependency file.
Files involved:
embed.js <- main script
dev2.js <- required custom script by embed.js
which reads this json file
fred.json renamed to chartio.json
embed.js code relevant to issue:
var http = require('http');
var jwt = require('jwt-simple');
var dashinfo = require('./dev2');
var ORGANIZATION_SECRET = dashinfo.getkey();
var ORG_ID = dashinfo.getorgid();
dev2.js code relevant to issue:
var mariadb = require('mariadb');
var connectioninfo = require('./chartio.json');
module.exports = {
getkey: function () {
return connectioninfo.connection.apikey;
},
getorgid: function () {
return connectioninfo.connection.orgid;
},
and finally, I have my charti0.json file which I cannot post due to sensitive data.
I assure you that everything was working until I renamed fred.json to chartio.json.
I have looked online to see if there is a way to clear the cache but I couldn't find anything that seemed to work, though I am a novice. I also looked at logs. I tried running this in IE and Chrome
This is what I see logged from the error:
Application has thrown an uncaught exception and is terminated:
Error: Cannot find module './fred.json'
Require stack:
- C:\xxx\xxx\GPS411\node\dev2.js
- C:\xxx\xxx\GPS411\node\embed.js
- C:\Program Files (x86)\iisnode\interceptor.js
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:794:15)
at Function.Module._load (internal/modules/cjs/loader.js:687:27)
at Module.require (internal/modules/cjs/loader.js:849:19)
at require (internal/modules/cjs/helpers.js:74:18)
at Object.<anonymous> (C:\Omnitracs\sylectus-trunk\GPS411\node\dev2.js:3:22)
at Module._compile (internal/modules/cjs/loader.js:956:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
at Module.load (internal/modules/cjs/loader.js:812:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Module.require (internal/modules/cjs/loader.js:849:19)
Folks, I was able to get this working by doing an old fashion workstation reboot. I changed the filename again to test if the issue returns and it seems to recognize the file changes now. I guess I was just stuck in cache-land, but now I'm free. Thanks for your consideration.
I am trying to create a chatbot for a VoIP solution using NodeJS, I recently refactored all conversation handlers in their separate scripts for ease of reading on the entry point.
Those conversation handlers are structured as follows:
// foobar.js
const Help = require('.../utils/Help.js');
const Utils = require('.../utils/Utils.js');
const UserList = require('.../database/Users.json');
module.exports = {
conversation: (message) => {
// Code here
}
// other cool methods
}
This is what my folder architecture looks like: (important files are *marked*)
/chatbot
/src
/bin
/conversation
*foobar.js*
foobarbar.js
etc.js
/database
*Users.json*
/utils
*Help.js*
*Utils.js*
/node_modules
To me, it seems like I target the files I require correctly, however, on runtime, I am greeted with a splendid error
internal/modules/cjs/loader.js:605
throw err;
^
Error: Cannot find module '.../utils/Help.js'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:603:15)
at Function.Module._load (internal/modules/cjs/loader.js:529:25)
at Module.require (internal/modules/cjs/loader.js:658:17)
at require (internal/modules/cjs/helpers.js:22:18)
at Object.<anonymous> (D:\Library\Documents\AIScroll\src\bin\conversation\foobar.js:1:76)
at Module._compile (internal/modules/cjs/loader.js:722:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:733:10)
at Module.load (internal/modules/cjs/loader.js:620:32)
at tryModuleLoad (internal/modules/cjs/loader.js:560:12)
at Function.Module._load (internal/modules/cjs/loader.js:552:3)
No matter how many dots I put in .../utils/Help.js, I always have the same error. Whether there is only one or there are fifteen.
I bet it's a really silly mistake, too.
Cheers ahead of time ♪
./ = Current folder
../ = One folder up
../../ = Two folders up and so on...
So your code needs to be as follows:
const Help = require('../../utils/Help.js');
const Utils = require('../../utils/Utils.js');
const UserList = require('../../database/Users.json');
Multiple dot's wont work. It's always either ./ or ../.
You can however write ../ multiple times.
It should be ../../utils/Help.js etc.
The utils folder is 2 directories up
I suppose you have to get up to 2 levels:
const Help = require('../../utils/Help.js');
const Utils = require('../../utils/Utils.js');
const UserList = require('../../database/Users.json');
I'm trying to connect to a Gremlin server with the JavaScript driver variant.
Up to package version 2.7.0, this is done easily by passing options to Gremlin.createClient() as in this example for Azure Cosmos DB:
const client = Gremlin.createClient(
config.port,
config.endpoint,
{
"session": false,
"ssl": true,
"user": `/dbs/${config.database}/colls/${config.collection}`,
"password": config.primaryKey
}
);
In newer versions of the package I can't get it done. The official docs suggest using gremlin.driver.auth.PlainTextSaslAuthenticator. However, that method seems to be not implemented in the package and returns TypeError: Cannot read property 'PlainTextSaslAuthenticator' of undefined
My test code (same config.js as in the working example):
const gremlin = require("gremlin");
const config = require("./config");
const Graph = gremlin.structure.Graph;
const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
const graph = new Graph();
const authenticator = new gremlin.driver.auth.PlainTextSaslAuthenticator(
`/dbs/${config.database}/colls/${config.collection}`,
config.primaryKey
);
const g = graph.traversal().withRemote(new DriverRemoteConnection(`ws://${config.endpoint}:${config.port}`, { authenticator });
Return:
C:\repos\gremlin-test\index.js:9
const authenticator = new gremlin.driver.auth.PlainTextSaslAuthenticator(
^
TypeError: Cannot read property 'PlainTextSaslAuthenticator' of undefined
at Object.<anonymous> (C:\repos\gremlin-test\index.js:9:47)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Function.Module.runMain (module.js:693:10)
at startup (bootstrap_node.js:191:16)
at bootstrap_node.js:612:3
Anyone know a solution to this?
I've not got too much experience with Gremlin.js, but I just downloaded it and have manually searched through all of its files - I can't find any trace of a PlainTextSaslAuthenticator function or its declaration.
This could mean one of two three -
Its function has been (accidentally) removed
It uses a third party package that has been (accidentally) removed
It has not been added to the package yet
Upon a swift Google search, I found this link which seems to show it being added to /lib/driver/auth, but that directory doesn't seem to exist in the package I got through npm install gremlin. Perhaps it is yet to be released?
I would therefore suggest you raise an issue on Github, but it seems that repository you linked doesn't allow for issues to be raised. So perhaps email/contact the author?
EDIT:
Thanks to Stephen for the link - the code hasn't been merged to the package yet. Keep track of it here.
Alright, so I've created a test project to show off this error. The error being that Node JS can't find my getStr function in my Another object.
This is the code:
test.js
var Another = require('./another.js');
var Other = require('./other.js');
var otherStr = Other.getStr();
console.log(otherStr);
other.js
var Another = require('./another.js');
var str = Another.getStr();
another.js
var Other = require('./other.js');
var str = "other String";
exports.getStr = function(){
return str;
}
And this is my output:
C:\Users\Admin\Desktop\JS DEV\NODE DEV\server\test>node test.js
C:\Users\Admin\Desktop\JS DEV\NODE DEV\server\test\other.js:3
var str = Another.getStr();
^
TypeError: Object #<Object> has no method 'getStr'
at Object.<anonymous> (C:\Users\Admin\Desktop\JS DEV\NODE DEV\server\test\ot
her.js:3:19)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at Object.<anonymous> (C:\Users\Admin\Desktop\JS DEV\NODE DEV\server\test\an
other.js:1:75)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
C:\Users\Admin\Desktop\JS DEV\NODE DEV\server\test>
So how do I get Node JS to see Another's getStr function in Other?
What you're dealing with here is a circular dependency. Node.js will let you load modules in a circular way but you need to design your code to account for it. Generally speaking, a circular dependency is a sign that the design is suffering from some flaw. In the code you've shown in the question, another requires other but does nothing with it. So the simplest fix would be to change another so that it does not require other.
If you have to keep the circular dependency for some reason or you want to experiment with circular dependencies for learning purposes, then this would be another possible fix:
var str = "other String";
exports.getStr = function(){
return str;
}
var Other = require('./other');
// Actually do something with Other down here.
By the time other is required another will at least have getStr available. So this takes care of the immediate issue. Note however that your other module does not export anything so your test.js file will still fail at var otherStr = Other.getStr(); Probably you forgot to add this:
exports.getStr = function(){
return str;
}
(Note: I've modified the require call so that it requires other without the .js suffix. Generally, you don't want to put suffixes in your require calls. You want to put a module name which Node can resolve to a file, a package, or something else.)