As you know, it's possible to access to exported variables and functions of the main js-file in the module, e. g.:
module1.js
export const MODULE1_CONSTANT1 = 'Test Const From the module1.js';
main.js
import { MODULE1_CONSTANT1 } from './module1';
console.log(MODULE1_CONSTANT1);
However: is it way to access to the main.js variables from the module1.js? I suppose, the answer will be same, so is it possible to exchange by variables between modules?
I know that it's not only JavaScript matter and project build system has the influence too, so let's consider Webpack in this question.
Use keyword require replace keyword import(because import MUST in top of source, it is ES6 syntax), and make a function to access each module, I think it can implement variables exchange between modules.
// module1.js
export const MODULE1_CONSTANT1 = 'Test Const From the module1.js';
export function MAIN_CONSTANT1() {
return require('./main').MAIN_CONSTANT1;
};
// main.js
export const MAIN_CONSTANT1 = 'Test Const From the main.js';
export function MODULE1_CONSTANT1() {
return require('./module1').MODULE1_CONSTANT1;
};
// hello.js
import {MAIN_CONSTANT1 as main_MAIN_CONSTANT1, MODULE1_CONSTANT1 as main_MODULE1_CONSTANT1} from './main';
import {MAIN_CONSTANT1 as module1_MAIN_CONSTANT1, MODULE1_CONSTANT1 as module1_MODULE1_CONSTANT1} from './module1';
console.log('main_MAIN_CONSTANT1', main_MAIN_CONSTANT1);
console.log('main_MODULE1_CONSTANT1', main_MODULE1_CONSTANT1());
console.log('module1_MAIN_CONSTANT1', module1_MAIN_CONSTANT1());
console.log('MODULE1_CONSTANT1', module1_MODULE1_CONSTANT1);
// output
// >>> MAIN_CONSTANT1 Test Const From the main.js
// >>> MODULE1_CONSTANT1 Test Const From the module1.js
// >>> module1_MAIN_CONSTANT1 Test Const From the main.js
// >>> module1_MODULE1_CONSTANT1 Test Const From the module1.js
Related
How to define a method 'foo' in a javascript file 'test.js' so that I can import that file into another javascript file and call the method 'foo'?
Before going further you'll need to figure out what kind of modules you're using, there're 2 common types of modules that I know CommonJS and ES
In either type of module you're using, in order for you to import your method, you will need to export it as a module first.
The details of their differences are found in the NodeJS document NodeJS Import
For the ES modules you can export your method 'foo' like this:
// normal function
export function foo1() {}
// arrow function
export const foo2 = () => {}
// or this grouping style that I prefer would look more elegant
function foo1() {}
const foo2 = () => {}
// we can export multiple methods at once
export {
foo1,
foo2
}
On the other hand, using the CommonJS module, you can export your method 'foo' like this:
// a single method
module.exports.foo1 = function() {}
module.exports = function foo2() {}
// multiple methods
module.exports = {
foo1: () => {},
foo2: () => {}
}
Once you've exported your methods as modules, you can now import them like this:
import { foo1, foo2 } from './test.js'
const exec = foo1();
or
import * as test from './test.js'
const exec = test.foo2();
Hope this help
Is it possible get individual "global" module for each instance?
import MyModule from './index.js';
const first = new MyModule();
const second = new MyModule();
// PLEASE SEE EXAMPLE BELOW FOR LOGS
// expect to log for both:
// 1. "in entry: true"
// 2. "in init: true"
// but second module logs:
// 1. "in entry: false"
// 2. "in init: false"
Issue being here that both share globals and 1. instance changes property to false.
What are my options to have in individual globals module per instance?
PS! I have tens of thousands of lines of legacy code. Would be 100x better if I didn't need to change/remove/refactor globals.js contents nor these imports import globals from './globals.js';. Nevertheless, give all your ideas - I need to fix it, even if I need to change a lot.
Code for example above / minimal reproducible example
index.js
import globals from './globals.js';
import init from './init.js';
export default function MyModule (conf) {
console.log('in entry:', globals.state1);
init();
}
globals.js
export default {
state1: true,
};
init.js
import globals from './globals.js';
export default function init () {
console.log('in init:', globals.state1);
globals.entry1 = false;
}
Since an object is passed by reference you need to create a copy each time you use globals.
A good way is to export a function like:
/* globals.js */
const globals = { // Maybe wrap the object in Object.freeze() to prevent side effects
state1: true,
};
export default () => ({ ...globals });
You can then call the function to create a copy each time you need it.
/* init.js */
import getGlobals from './globals.js';
export default function init () {
const globals = getGlobals();
console.log('in init:', globals.state1);
globals.entry1 = false;
}
Guided by eslint's prefer-destructuring rule, I defined some constants like this:
const {
NODE_ENV,
API_URL,
} = process.env;
Is it possible to export these constants by prefixing the statement by export?
export const {
NODE_ENV,
API_URL,
} = process.env;
This would seem natural, but eslint-plugin-import complains about a violation of the import/named rule: API_URL not found in '../constants'. In fact, this usage of export is also not described on the relevant MDN page.
Do we then have to repeat all constants in a separate export statement?
const {
NODE_ENV,
API_URL,
} = process.env;
export {
NODE_ENV,
API_URL,
};
Is it possible to export these constants by prefixing the statement by
export?
export const {
NODE_ENV,
API_URL,
} = process.env;
Yes, this is totally valid according to the spec. You can use destructuring patterns in the declarations of exported consts.
This would seem natural, but
eslint-plugin-import
complains about a violation of the
import/named
rule: API_URL not found in '../constants'.
Sounds like that plugin is broken. In fact, your exact use case was reported as working before.
Article 15.2.2.3 of the spec says:
...
ExportDeclaration : export VariableStatement
ExportDeclaration : export Declaration
Article 13.1.4 says:
Declaration : LexicalDeclaration
Article 13.3 says:
LexicalDeclaration:
LetOrConst BindingList;
LetOrConst :
let
const
BindingList :
LexicalBinding
BindingList, LexicalBinding
LexicalBinding:
BindingPattern Initializer
Therefore this:
// ExportDeclaration
export // export
// Declaration
// LexicalDeclaration:
const // LetOrConst
// LexicalBindingList
// LexicalBinding
{ NODE_ENV, API_URL } // BindingPattern
= process.env; // Initializer
is totally valid JavaScript.
I'll start with the setup, before I get into the problem. Let's start with the base file whose named exports we'll want to spy on:
// fileA.js
export function bar() {}
export function foo() {}
And then have two variations of classes that import these, one in CommonJS style, and one in ES6 style:
// es6Baz.js
import * as A from 'fileA'
export default class Baz {
callFoo() { A.foo(); }
}
// commonBaz.js
const A = require('fileA');
export default class Baz {
callFoo() { A.foo(); }
}
Then likewise, test files for these two same variants:
// testEs6A.js
import Baz from 'es6Baz';
import * as A from 'fileA';
it('test', () => {
spyOn(A, 'foo');
const b = new Baz();
b.callFoo();
expect(A.foo).toHaveBeenCalled(); // this will fail
});
// testCommonA.js
import Baz from 'es6Baz';
const A = require('fileA');
it('test', () => {
spyOn(A, 'foo');
const b = new Baz();
b.callFoo();
expect(A.foo).toHaveBeenCalled(); // this will pass
});
The main question here is: why does mocking work with the CommonJS approach, but not the ES6 one, assuming we're using Babel to compile?
My understanding was that ES6 live binds, while CommonJS copies, so I was surprised the former failed, and even more surprised the latter succeeded. My best guess is that a * import results in a locally namespaced object that's different in the files this is done in (i.e. A in es6Baz.js is not the same as A in testEst6A.js), but is that actually the case? And why would the require work, when this doesn't?
index.js of imported npm module myLib
const Mod1 = require('./mod1');
const Mod2 = require('./mod2');
const Mod3 = require('./mod3');
module.exports = {
Mod1,
Mod2,
Mod3,
};
mod1.js
class Mod1 {
constructor(url) {
}
}
file using the above npm module
const Mod1 = require('myLib');
const instance = new Mod1();
This is throwing the following error when trying to run it:
const instance = new Mod1();
^
TypeError: Mod1 is not a constructor
How should I reference the class from a single import index.js so that I may be able to create an instance of the class?
There seems to be a slight mistake in your import, the actual import will be like:
const {Mod1} = require('myLib');
which will pull the class from the file and give it to you (ES6 feature)
you can also do it like:
const Mod1 = require('myLib').Mod1;
hope this helps.