rewire
rewire copied to clipboard
global variable is not available in the module
Hi, I'm trying to add a non-exported 3rd party class to global scope, using rewire
The class looks like this: https://github.com/Dogfalo/materialize/blob/v1-dev/js/component.js
I'm doing it this way:
const ComponentModule = require('rewire')('materialize-css/js/component');
global.Component = ComponentModule.__get__('Component');
And it almost works, but inside component.js, there are usages of Element
and cash
. And during runtime, they fail as "is not defined"
I managed to solve the problem by:
const ComponentModule = require('rewire')('materialize-css/js/component');
ComponentModule.__set__('Element', Element);
ComponentModule.__set__('cash', cash);
global.Component = ComponentModule.__get__('Component');
And it works.
However, it seems very strange to me, since both of these variables are available before rewiring. Is there any way to add these globals implicitly?
I think it might be the same problem: #99
What do you mean with 'both of these variables are available before rewiring'? Looking at the source code of component.js
, they don't get declared or imported there, so somehow they have been declared before when running Materialize in the usual way.
Even if in the file you are currently working in, you have declared Element
and cash
, that doesn't mean rewire makes them automagically available to component.js
(nor should it, else you would get a very confusing mess of implicitly declared globals). So I don't think there is an issue with rewire, and your fix seems the way to go.
Hi @rensbaardman, thanks for the answer.
Even if in the file you are currently working in, you have declared Element and cash, that doesn't mean rewire makes them automagically available to component.js
I didn't declare them locally. They are already available in the global declarations. The example which I gave here is the full listing of the file.
Hi @rensbaardman, thanks for the answer.
Even if in the file you are currently working in, you have declared Element and cash, that doesn't mean rewire makes them automagically available to component.js
I didn't declare them locally. They are already available in the global declarations. The example which I gave here is the full listing of the file.
I see. Element
is part of a standard webbrowser environment, cash
seems to be a utility which has been loading into a webpage. But are you using this with Node? Then where do these globals get declared? Because they are not standard Node globals.
The problem probably lies with the different scope of component.js
. Are you sure Element
and cash
get defined as globals? Because then component.js
should have access to them.
By the way, I have to say that modifying the global
variable is probably not the way to go for exporting Component
. It's usually cleaner to use the module.exports
-pattern.
Hi @rensbaardman, sorry, I had to provide a little bit more context: I was writing Jest tests, with node + jsdom
My file (which I test) depends on 3rd party materializecss library. This library is quite old-school and doesn't export much. In most cases it relies on global nature of declarations inside a browser. I.e. it just sets window.abc = abc
(for example, the cash function), usually.
Or declares a class without any exports (as in this source)
And my file depends on a Select
class, from this library, which depends on global Component
class, which depends on global cash
method.
Also, all of them depend on the global Element
class
Are you sure Element and cash get defined as globals? Because then component.js should have access to them.
I had a setup.js file for Jest (it's just any file, which runs before any tests) which looked like this:
import 'materialize-css/js/cash';
const ComponentModule = require('rewire')('materialize-css/js/component');
global.Component = ComponentModule.__get__('Component');
I could assume, that this import could be available only inside setup.js
But as you can see, I don't do anything with Element
here, it comes from jsdom
, which I don't import here at all (it's already injected by Jest).
By the way, I have to say that modifying the global variable is probably not the way to go for exporting Component. It's usually cleaner to use the module.exports-pattern.
The problem, that I'm not using this class directly. It's used in another .js from that library (e.g. select.js:13) Otherwise, I fully agree with you, I try to use exports/imports where it's possible
Alright, but where/how are Element
and cash
defined as globals? Because if Jest injects Element
into your test, then that (probably) doesn't make it global. And import
ing cash
also doesn't make it global. So then it is expected that component.js
doesn't have access to it.
Maybe I'm confusing something here, I'm not that good with JS. Here is my reasoning, may be I understand JS variable scoping wrong:
I don't know how Jest (or jsdom) injects the Element
in my setup and tests. But this Element
is also accessible in all 3rd party imported modules. I don't think, that Jest will inject Element
everywhere
Also, Jest has no clue about cash
, I just import it in one place and it magically works everywhere, except that component.js rewiring :(
I believe it's defined as a global this way (first lines in cash.js):
(function (factory) {
window.cash = factory();
})
Also, if I remember correctly, I tried to debug this rewiring. Before entering require('rewire')
I added a watch on global.Element
and global.cash
and they were there. However, somewhere during rewire initialisation, those globals became undefined.
And then somewhere during method call chain of rewire, these watches became undefined.
PS thanks for your time and trying to understand the issue!
Hmmm... that's interesting. I wouldn't know why calling rewire()
would undefine global variables. I think I now understand what your problem is 😅 And now I see why it could be related to #99. If you could make a minimal reproducible example, that might help sorting this thing out!
Hi @rensbaardman could you check this one, please? https://github.com/bugy/rewire-181
There is an entry point: case_181.test.js, where I import a file, which sets global variable Then I rewire a class And then I print global variable from 3 places:
- common util
- rewired class
- test
Only rewired class fails to print it
npm run test
Output:
someGlobalVar in test: abc
someGlobalVar in MyClass: undefined
someGlobalVar in another_file: abc