I am using Babel to compile some ES6 JavaScript down to ES5. I am having some trouble with my code because my modules are being evaluated in an undefined order.
Let's say I have a modules:
// a.js
class A {
constructor() {
this.prop = window.randomProperty;
console.log("Prop " + this.prop);
}
}
const a = new A();
export default a;
This module relies on window.randomProperty to be set before it can instantiate itself.
Now I have a main file:
// main.js
import "babel-polyfill"; // Not sure if this is relevant
window.randomProperty = function() { return "hi"; };
console.log("randomProperty set");
import A from "a";
The console output of this is:
Prop undefined
randomProperty set
How can I have the code execute in the correct order?
import statements are hoisted, so imports are loaded before your code is executed. To execute it in order you want, you should use other module loader such as using require.
const A = require("a");
Imports are loaded (and executed, unless cyclic) before the module is executed statically. In your case, a.js will be loaded before main.js is executed.
If you have dependencies, you should declare them explicitly:
// random_prop.js
window.randomProperty = function() { return "hi"; };
console.log("randomProperty set");
// a.js
import "random_prop";
const a = {
prop: window.randomProperty;
}
console.log("Prop " + a.prop);
export {a as default}
// main.js
import "babel-polyfill"; // Not sure if this is relevant
import a from "a";
console.log(a.prop);
Of course, you could also import the random_prop.js in main.js before a.js, and it would work in this simple setting, but I would not recommend relying on side effects like that.
Your problem lies in where you instantiate A, try doing it in main.js. Check this out:
// a.js
class A {
constructor() {
this.prop = window.randomProperty;
console.log("Prop " + this.prop);
}
}
// do not instantiate here
// const a = new A();
export default a;
Just make sure you create the object here:
// main.js
import A from "a";
window.randomProperty = function() { return "hi"; };
console.log("randomProperty set");
const a = new A();
The reason is, when you import a module, it will invoke any methods that are not tied to a function or class definition.
Hope this helps!
Related
I've been working with nodejs lately and still getting to grips with the module system, so apologies if this is an obvious question. I want code roughly like the below:
a.js (the main file run with node)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var a = require("./a");
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
My problem seems to be that I can't access the instance of ClassA from within an instance of ClassB.
Is there any correct / better way to structure modules to achieve what I want?
Is there a better way to share variables across modules?
Try to set properties on module.exports, instead of replacing it completely. E.g., module.exports.instance = new ClassA() in a.js, module.exports.ClassB = ClassB in b.js. When you make circular module dependencies, the requiring module will get a reference to an incomplete module.exports from the required module, which you can add other properties latter on, but when you set the entire module.exports, you actually create a new object which the requiring module has no way to access.
While node.js does allow circular require dependencies, as you've found it can be pretty messy and you're probably better off restructuring your code to not need it. Maybe create a third class that uses the other two to accomplish what you need.
[EDIT] it's not 2015 and most libraries (i.e. express) have made updates with better patterns so circular dependencies are no longer necessary. I recommend simply not using them.
I know I'm digging up an old answer here...
The issue here is that module.exports is defined after you require ClassB.
(which JohnnyHK's link shows)
Circular dependencies work great in Node, they're just defined synchronously.
When used properly, they actually solve a lot of common node issues (like accessing express.js app from other files)
Just make sure your necessary exports are defined before you require a file with a circular dependency.
This will break:
var ClassA = function(){};
var ClassB = require('classB'); //will require ClassA, which has no exports yet
module.exports = ClassA;
This will work:
var ClassA = module.exports = function(){};
var ClassB = require('classB');
I use this pattern all the time for accessing the express.js app in other files:
var express = require('express');
var app = module.exports = express();
// load in other dependencies, which can now require this file and use app
Sometimes it is really artificial to introduce a third class (as JohnnyHK advises), so in addition to Ianzz:
If you do want to replace the module.exports, for example if you're creating a class (like the b.js file in the above example), this is possible as well, just make sure that in the file that is starting the circular require, the 'module.exports = ...' statement happens before the require statement.
a.js (the main file run with node)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
var a = require("./a"); // <------ this is the only necessary change
The solution is to 'forward declare' your exports object before requiring any other controller. So if you structure all your modules like this and you won't run into any issues like that:
// Module exports forward declaration:
module.exports = {
};
// Controllers:
var other_module = require('./other_module');
// Functions:
var foo = function () {
};
// Module exports injects:
module.exports.foo = foo;
What about lazy requiring only when you need to? So your b.js looks as follows
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
var a = require("./a"); //a.js has finished by now
util.log(a.property);
}
module.exports = ClassB;
Of course it is good practice to put all require statements on top of the file. But there are occasions, where I forgive myself for picking something out of an otherwise unrelated module. Call it a hack, but sometimes this is better than introducing a further dependency, or adding an extra module or adding new structures (EventEmitter, etc)
You can solve this easily: just export your data before you require anything else in modules where you use module.exports:
classA.js
class ClassA {
constructor(){
ClassB.someMethod();
ClassB.anotherMethod();
};
static someMethod () {
console.log( 'Class A Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassA;
var ClassB = require( "./classB.js" );
let classX = new ClassA();
classB.js
class ClassB {
constructor(){
ClassA.someMethod();
ClassA.anotherMethod();
};
static someMethod () {
console.log( 'Class B Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassB;
var ClassA = require( "./classA.js" );
let classX = new ClassB();
A solution which require minimal change is extending module.exports instead of overriding it.
a.js - app entry point and module which use method do from b.js*
_ = require('underscore'); //underscore provides extend() for shallow extend
b = require('./b'); //module `a` uses module `b`
_.extend(module.exports, {
do: function () {
console.log('doing a');
}
});
b.do();//call `b.do()` which in turn will circularly call `a.do()`
b.js - module which use method do from a.js
_ = require('underscore');
a = require('./a');
_.extend(module.exports, {
do: function(){
console.log('doing b');
a.do();//Call `b.do()` from `a.do()` when `a` just initalized
}
})
It will work and produce:
doing b
doing a
While this code will not work:
a.js
b = require('./b');
module.exports = {
do: function () {
console.log('doing a');
}
};
b.do();
b.js
a = require('./a');
module.exports = {
do: function () {
console.log('doing b');
}
};
a.do();
Output:
node a.js
b.js:7
a.do();
^
TypeError: a.do is not a function
The important thing is not to re-assign the module.exports object that you have been given, because that object may have already been given to other modules in the cycle! Just assign properties inside module.exports and other modules will see them appear.
So a simple solution is:
module.exports.firstMember = ___;
module.exports.secondMember = ___;
The only real downside is the need to repeat module.exports. many times.
Similar to lanzz and setec's answers, I have been using the following pattern, which feels more declarative:
module.exports = Object.assign(module.exports, {
firstMember: ___,
secondMember: ___,
});
The Object.assign() copies the members into the exports object that has already been given to other modules.
The = assignment is logically redundant, since it is just setting module.exports to itself, but I am using it because it helps my IDE (WebStorm) to recognise that firstMember is a property of this module, so "Go To -> Declaration" (Cmd-B) and other tooling will work from other files.
This pattern is not very pretty, so I only use it when a cyclic dependency issue needs to be resolved.
It is fairly well suited to the reveal pattern, because you can easily add and remove exports from the object, especially when using ES6's property shorthand.
Object.assign(module.exports, {
firstMember,
//secondMember,
});
the extremely simple solution is often:
usually you'd have the require at the top of the file ...
var script = require('./script')
function stuff() {
script.farfunction()
}
instead, just require it "in the function"
function stuff() {
var _script = require('./script')
_script.farfunction()
}
An other method I've seen people do is exporting at the first line and saving it as a local variable like this:
let self = module.exports = {};
const a = require('./a');
// Exporting the necessary functions
self.func = function() { ... }
I tend to use this method, do you know about any downsides of it?
TL;DR
Just use exports.someMember = someMember instead of module.exports = { // new object }.
Extended Answer
After reading lanzz's response I could finally figure it out what is happening here, so I'll give my two cents on the subject, extending his answer.
Let's see this example:
a.js
console.log("a starting");
console.log("a requires b");
const b = require("./b");
console.log("a gets b =", b);
function functionA() {
console.log("function a");
}
console.log("a done");
exports.functionA = functionA;
b.js
console.log("b starting");
console.log("b requires a");
const a = require("./a");
console.log("b gets a =", a);
function functionB() {
console.log("On b, a =", a)
}
console.log("b done");
exports.functionB = functionB;
main.js
const a = require("./a");
const b = require("./b");
b.functionB()
Output
a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = { functionA: [Function: functionA] }
Here we can see that at first b receives an empty object as a, and then once a is fully loaded, that reference is updated through exports.functionA = functionA. If you instead replace the entire module with another object, through module.exports, then b will lose the reference from a, since it will point out to the same empty object from the beginning, instead of pointing to the new one.
So if you export a like this: module.exports = { functionA: functionA }, then the output will be:
a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = {} // same empty object
Actually I ended up requiring my dependency with
var a = null;
process.nextTick(()=>a=require("./a")); //Circular reference!
not pretty, but it works. It is more understandable and honest than changing b.js (for example only augmenting modules.export), which otherwise is perfect as is.
Here is a quick workaround that I've found use full.
On file 'a.js'
let B;
class A{
constructor(){
process.nextTick(()=>{
B = require('./b')
})
}
}
module.exports = new A();
On the file 'b.js' write the following
let A;
class B{
constructor(){
process.nextTick(()=>{
A = require('./a')
})
}
}
module.exports = new B();
This way on the next iteration of the event loop classes will be defined correctly and those require statements will work as expected.
One way to avoid it is to don't require one file in other just pass it as an argument to a function what ever you need in an another file.
By this way circular dependency will never arise.
If you just can't eliminate circular dependencies (e.g useraccount <---> userlogin), there's one more option...
Its as simple as using setTimeout()
//useraccount.js
let UserLogin = {};
setTimeout(()=>UserLogin=require('./userlogin.js'), 10);
class UserAccount{
getLogin(){
return new UserLogin(this.email);
}
}
//userlogin.js
let UserAccount ={};
setTimeout(()=>UserAccount=require('./useraccount.js'), 15);
class UserLogin{
getUser(){
return new User(this.token);
}
}
I looked at similar questions/answers but they are different from my question or my setup.
I've a class B that extends class A and writing a test for the class B.
src folder
src/a/A.js
export default class A {
// implementation
}
src/b/B.js
import A from "../a/A" // -> SyntaxError: Cannot use import statement outside a module
export default class B extends A {
constructor() {
}
}
test folder
describe("BTest", function(){
let assert = require("assert");
describe("testConstructor", function(){
let B = require("../src/b/B");
let b = new B();
assert(b != null)
});
});
You appear to be running in a node environment. Node doesn't support import/export. You’ll need to either use require and module.exports or transpile your code using Babel.
I've been working with nodejs lately and still getting to grips with the module system, so apologies if this is an obvious question. I want code roughly like the below:
a.js (the main file run with node)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var a = require("./a");
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
My problem seems to be that I can't access the instance of ClassA from within an instance of ClassB.
Is there any correct / better way to structure modules to achieve what I want?
Is there a better way to share variables across modules?
Try to set properties on module.exports, instead of replacing it completely. E.g., module.exports.instance = new ClassA() in a.js, module.exports.ClassB = ClassB in b.js. When you make circular module dependencies, the requiring module will get a reference to an incomplete module.exports from the required module, which you can add other properties latter on, but when you set the entire module.exports, you actually create a new object which the requiring module has no way to access.
While node.js does allow circular require dependencies, as you've found it can be pretty messy and you're probably better off restructuring your code to not need it. Maybe create a third class that uses the other two to accomplish what you need.
[EDIT] it's not 2015 and most libraries (i.e. express) have made updates with better patterns so circular dependencies are no longer necessary. I recommend simply not using them.
I know I'm digging up an old answer here...
The issue here is that module.exports is defined after you require ClassB.
(which JohnnyHK's link shows)
Circular dependencies work great in Node, they're just defined synchronously.
When used properly, they actually solve a lot of common node issues (like accessing express.js app from other files)
Just make sure your necessary exports are defined before you require a file with a circular dependency.
This will break:
var ClassA = function(){};
var ClassB = require('classB'); //will require ClassA, which has no exports yet
module.exports = ClassA;
This will work:
var ClassA = module.exports = function(){};
var ClassB = require('classB');
I use this pattern all the time for accessing the express.js app in other files:
var express = require('express');
var app = module.exports = express();
// load in other dependencies, which can now require this file and use app
Sometimes it is really artificial to introduce a third class (as JohnnyHK advises), so in addition to Ianzz:
If you do want to replace the module.exports, for example if you're creating a class (like the b.js file in the above example), this is possible as well, just make sure that in the file that is starting the circular require, the 'module.exports = ...' statement happens before the require statement.
a.js (the main file run with node)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
var a = require("./a"); // <------ this is the only necessary change
The solution is to 'forward declare' your exports object before requiring any other controller. So if you structure all your modules like this and you won't run into any issues like that:
// Module exports forward declaration:
module.exports = {
};
// Controllers:
var other_module = require('./other_module');
// Functions:
var foo = function () {
};
// Module exports injects:
module.exports.foo = foo;
What about lazy requiring only when you need to? So your b.js looks as follows
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
var a = require("./a"); //a.js has finished by now
util.log(a.property);
}
module.exports = ClassB;
Of course it is good practice to put all require statements on top of the file. But there are occasions, where I forgive myself for picking something out of an otherwise unrelated module. Call it a hack, but sometimes this is better than introducing a further dependency, or adding an extra module or adding new structures (EventEmitter, etc)
You can solve this easily: just export your data before you require anything else in modules where you use module.exports:
classA.js
class ClassA {
constructor(){
ClassB.someMethod();
ClassB.anotherMethod();
};
static someMethod () {
console.log( 'Class A Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassA;
var ClassB = require( "./classB.js" );
let classX = new ClassA();
classB.js
class ClassB {
constructor(){
ClassA.someMethod();
ClassA.anotherMethod();
};
static someMethod () {
console.log( 'Class B Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassB;
var ClassA = require( "./classA.js" );
let classX = new ClassB();
A solution which require minimal change is extending module.exports instead of overriding it.
a.js - app entry point and module which use method do from b.js*
_ = require('underscore'); //underscore provides extend() for shallow extend
b = require('./b'); //module `a` uses module `b`
_.extend(module.exports, {
do: function () {
console.log('doing a');
}
});
b.do();//call `b.do()` which in turn will circularly call `a.do()`
b.js - module which use method do from a.js
_ = require('underscore');
a = require('./a');
_.extend(module.exports, {
do: function(){
console.log('doing b');
a.do();//Call `b.do()` from `a.do()` when `a` just initalized
}
})
It will work and produce:
doing b
doing a
While this code will not work:
a.js
b = require('./b');
module.exports = {
do: function () {
console.log('doing a');
}
};
b.do();
b.js
a = require('./a');
module.exports = {
do: function () {
console.log('doing b');
}
};
a.do();
Output:
node a.js
b.js:7
a.do();
^
TypeError: a.do is not a function
The important thing is not to re-assign the module.exports object that you have been given, because that object may have already been given to other modules in the cycle! Just assign properties inside module.exports and other modules will see them appear.
So a simple solution is:
module.exports.firstMember = ___;
module.exports.secondMember = ___;
The only real downside is the need to repeat module.exports. many times.
Similar to lanzz and setec's answers, I have been using the following pattern, which feels more declarative:
module.exports = Object.assign(module.exports, {
firstMember: ___,
secondMember: ___,
});
The Object.assign() copies the members into the exports object that has already been given to other modules.
The = assignment is logically redundant, since it is just setting module.exports to itself, but I am using it because it helps my IDE (WebStorm) to recognise that firstMember is a property of this module, so "Go To -> Declaration" (Cmd-B) and other tooling will work from other files.
This pattern is not very pretty, so I only use it when a cyclic dependency issue needs to be resolved.
It is fairly well suited to the reveal pattern, because you can easily add and remove exports from the object, especially when using ES6's property shorthand.
Object.assign(module.exports, {
firstMember,
//secondMember,
});
the extremely simple solution is often:
usually you'd have the require at the top of the file ...
var script = require('./script')
function stuff() {
script.farfunction()
}
instead, just require it "in the function"
function stuff() {
var _script = require('./script')
_script.farfunction()
}
An other method I've seen people do is exporting at the first line and saving it as a local variable like this:
let self = module.exports = {};
const a = require('./a');
// Exporting the necessary functions
self.func = function() { ... }
I tend to use this method, do you know about any downsides of it?
TL;DR
Just use exports.someMember = someMember instead of module.exports = { // new object }.
Extended Answer
After reading lanzz's response I could finally figure it out what is happening here, so I'll give my two cents on the subject, extending his answer.
Let's see this example:
a.js
console.log("a starting");
console.log("a requires b");
const b = require("./b");
console.log("a gets b =", b);
function functionA() {
console.log("function a");
}
console.log("a done");
exports.functionA = functionA;
b.js
console.log("b starting");
console.log("b requires a");
const a = require("./a");
console.log("b gets a =", a);
function functionB() {
console.log("On b, a =", a)
}
console.log("b done");
exports.functionB = functionB;
main.js
const a = require("./a");
const b = require("./b");
b.functionB()
Output
a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = { functionA: [Function: functionA] }
Here we can see that at first b receives an empty object as a, and then once a is fully loaded, that reference is updated through exports.functionA = functionA. If you instead replace the entire module with another object, through module.exports, then b will lose the reference from a, since it will point out to the same empty object from the beginning, instead of pointing to the new one.
So if you export a like this: module.exports = { functionA: functionA }, then the output will be:
a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = {} // same empty object
Actually I ended up requiring my dependency with
var a = null;
process.nextTick(()=>a=require("./a")); //Circular reference!
not pretty, but it works. It is more understandable and honest than changing b.js (for example only augmenting modules.export), which otherwise is perfect as is.
Here is a quick workaround that I've found use full.
On file 'a.js'
let B;
class A{
constructor(){
process.nextTick(()=>{
B = require('./b')
})
}
}
module.exports = new A();
On the file 'b.js' write the following
let A;
class B{
constructor(){
process.nextTick(()=>{
A = require('./a')
})
}
}
module.exports = new B();
This way on the next iteration of the event loop classes will be defined correctly and those require statements will work as expected.
One way to avoid it is to don't require one file in other just pass it as an argument to a function what ever you need in an another file.
By this way circular dependency will never arise.
If you just can't eliminate circular dependencies (e.g useraccount <---> userlogin), there's one more option...
Its as simple as using setTimeout()
//useraccount.js
let UserLogin = {};
setTimeout(()=>UserLogin=require('./userlogin.js'), 10);
class UserAccount{
getLogin(){
return new UserLogin(this.email);
}
}
//userlogin.js
let UserAccount ={};
setTimeout(()=>UserAccount=require('./useraccount.js'), 15);
class UserLogin{
getUser(){
return new User(this.token);
}
}
What's the ES6 equivalent for module.exports
I want to get the value of foo from an import statement
module.exports = {
foo: function (a) {
}
}
Tried:
export default {
foo: function (a) {
}
}
The way first one is imported is using:
var file;
var filename = root + "/" + fileStats.name;
file = require(path.resolve(filename));
I want to use ES6 import statement. I read somewhere that this isn't supported however would like to still know if there's a work around this.
Not sure what you're trying to do because in the code you supplied you did not consume the actual foo method from the object you imported.
But if I understand correctly, you could achieve this in one of 2 ways:
export default function foo(a) { };
and consume the module with:
import foo from './<filename>.js';
Or alternatively, don't use the default export:
export function foo(a) {};
and consume with:
import { foo } from './<filename>.js';
This is a follow-up question to In Node.js, how do I "include" functions from my other files?
I would like to include an external js file that contains common functions for a node.js app.
From one of the answers in In Node.js, how do I "include" functions from my other files?, this can be done by
// tools.js
// ========
module.exports = {
foo: function () {
// whatever
},
bar: function () {
// whatever
}
};
var zemba = function () {
}
It is inconvenient to export each and every function. Is it possible to have a one-liner that exports all functions? Something that looks like this;
module.exports = 'all functions';
It is so much more convenient this way. It is also less buggy in case one forgets to export certain functions later.
If not a one-liner, are there simpler alternatives that make coding more convenient? I just want to include an external js file made up of common functions conveniently. Something like include <stdio.h> in C/C++.
You can write all your function declarations first and then export them in an object:
function bar() {
//bar
}
function foo() {
//foo
}
module.exports = {
foo, bar
};
There's no magical one-liner though, you need to explicitly export the functions you want to be public.
I have done something like the following:
var Exported = {
someFunction: function() { },
anotherFunction: function() { },
}
module.exports = Exported;
I require it in another file and I can access those functions
var Export = require('path/to/Exported');
Export.someFunction();
This is essentially just an object with functions in it, and then you export the object.
A really old question but I just had to solve the same issue myself.
the solution I used was to define a Class inside the module to contain all my functions and simply export an instance of the class.
classes.js looks like this:
class TestClass
{
Function1() {
return "Function1";
}
Function2() {
return "Function2";
}
}
module.exports = new TestClass();
app.js looks like this:
const TestClass = require("./classes");
console.log( TestClass.Function1);
just keep adding more functions to the class and they will be exported :)
It is worth noting that in ES6, you can now export functions like this:
export function foo(){}
export function bar(){}
function zemba(){}
Simply write export before the functions you want to export. More information here.
If you use ES6 you can do something like that:
function bar() {
//bar
}
function foo() {
//foo
}
export default { bar, foo };
const fs = require("fs")
var ExportAll = {
deleteFile : function deleteFile(image,folder="uploads"){
let imagePath = `public/${folder}/${image}`
if (fs.existsSync(imagePath)){
fs.unlinkSync(imagePath)
}
},
checkFile : function checkFile(image,folder="uploads"){
let imagePath = `public/${folder}/${image}`
if (fs.existsSync(imagePath)){
return true
}
else{
return false
}
},
rand : function(min=1,max=10)
{
return Math.floor((Math.random() * max) + min)
}
}
module.exports = ExportAll
Import everything from a type module file that has functions that are exported.
Found here:
https://javascript.info/import-export
myfile.js
export function myFunction()
{
// ................
}
export function myFunction2()
{
// ................
}
myfile2.js - import everything that is exported in the file
import * as myFunctions from './myfile.js';
// Usage
myFunctions.myFunction();
myFunctions.myFunction2();