I use webstorm ide with nodejs. When I create modules and require them, I don't have code completion.
For example:
test.js
/** #module test*/
module.exports = {
run: function () {}
};
main.js
var test = require(__dirname+"/test.js");
test. //code completion does not offer "run"
I haven't found anything about module usages in jsdoc 3 documentation yet. :S
var test = require("./test.js");
test. //code completion offers "run"
So you have to use "." instead of __dirname.
Related
I was trying to run some NodeJS code using QickJS and NectarJS, and I stumble in an old question I have, how to import modules.
In special, qjs -m <source-js> loads ES6 modules, and expect import export statements,, instead of require, and writing module.exports, or exports.
Also I use an builtin std module (that cannot be resolved by node_module).
For the first example I changed the code manually, but I would like to have a script to do the transformations. I expected this to be doable with webpack, but I can't find how.
Example
main.js
const h = require('./hello.js');
h.sayHello();
hello.js
const h = require('./print.js');
function sayHello(){
h.print("Hello");
}
module.exports = {sayHello};
print.js
module.exports = {
print(s) {
console.log(s);
}
}
I can run this with the command node main.js, but qjs -m main.js, will fail with 'require' is not defined
In this question that I asked here:
Why does mutating a module update the reference if calling that module from another module, but not if calling from itself?
I'm asking about the nature of module mutation.
However as it it turns out, ES6 modules can't actually be mutated - all of their properties are treated as constants. (See this answer)
But somehow - when Jest tests modules - they can be mutated, and that's how Jest allows for mocking.
How is this happening?
I imagine that it's a babel plugin that that's running - transpiling the module to CommonJS modules? Is there any documentation about this?
Is there a way to view the transpiled code?
ES6 modules can't actually be mutated - all of their properties are treated as constants.
Interesting. You're right, even something as simple as this:
import * as lib from "./lib"; // import an ES6 module
const spy = jest.spyOn(lib, 'someFunc'); // spy on someFunc
...technically shouldn't be allowed since jest.spyOn replaces the method on the object with a spy and lib.someFunc should be a binding to someFunc in the ES6 module.
But somehow - when Jest tests modules - they can be mutated, and that's how Jest allows for mocking.
How is this happening?
They can only be mutated because Jest isn't actually using ES6 modules.
(I guess for completeness it might be possible to run Jest using actual ES6 modules by using Node's experimental support for ES6 Modules but I haven't tried).
I imagine that it's a babel plugin that that's running - transpiling the module...Is there any documentation about this?
"babel-jest is automatically installed when installing Jest and will automatically transform files if a babel configuration exists in your project. To avoid this behavior, you can explicitly reset the transform configuration option".
So by default Jest will use babel-jest which transpiles the source code using babel (and does a few other things like hoisting calls to jest.mock).
Note that Jest can be also be configured using transform which maps "regular expressions to paths to transformers".
Is there a way to view the transpiled code?
Yes. Transformations are done in jest-runtime here and the output is saved to a cache here.
The easiest way to look at the transpiled code is to view the cache.
You can do that by running Jest with the --showConfig option which will output the config used when running Jest. The cache location can be found by looking at the value of "cacheDirectory".
Then run Jest with the --clearCache option to clear out the cache.
Finally, run Jest normally and the cache directory will contain the transpiled code for your project.
Example
The latest Jest (v24) will transpile this code:
// lib.js
export const someFunc = () => 1;
// code.js
import { someFunc } from './lib';
export const func = () => someFunc() + 1;
// code.test.js
import { func } from './code';
import * as lib from './lib';
test('func', () => {
const spy = jest.spyOn(lib, 'someFunc');
func();
expect(spy).toHaveBeenCalled(); // SUCCESS
});
...to this:
// lib.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.someFunc = void 0;
const someFunc = () => 1;
exports.someFunc = someFunc;
// code.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.func = void 0;
var _lib = require("./lib");
const func = () => (0, _lib.someFunc)() + 1;
exports.func = func;
// code.test.js
"use strict";
var _code = require("./code");
var lib = _interopRequireWildcard(require("./lib"));
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
test('func', () => {
const spy = jest.spyOn(lib, 'someFunc');
(0, _code.func)();
expect(spy).toHaveBeenCalled(); // SUCCESS
});
The import * as lib from 'lib'; line gets handled by _interopRequireWildcard which uses require under the hood.
Every call to require "will get exactly the same object returned, if it would resolve to the same file" so code.js and code.test.js are getting the same object from require('./lib').
someFunc is exported as exports.someFunc which allows it to be reassigned.
So yes, you're exactly right. Spying (or mocking) like this only works because the ES6 modules are getting transpiled by babel into Node modules in a way that allows them to be mutated.
My problem is the following:
I use gulp+browserify to compile my TypeScript to JavaScript that you can use on normal HTML pages, the problem is that my class is never available on the browser:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
This is my TypeScript File:
class Test {
public test(): void {
console.log("aa");
}
}
This is my gulpfile
var gulp = require("gulp");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");
gulp.task("default", function () {
return browserify({
//basedir: '.',
debug: true,
entries: ['app/Resources/typescript/Test.ts'],
cache: {},
packageCache: {}
})
.plugin(tsify)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest("web/bundles/framework/js"));
});
The file compiles without problem, and is included in my index.html (the compiled js file).
But when i try:
var t = new Test();
I get the following error:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
I can't resolve it, I have read a lot and I haven't found anything clear, I tried all and nothing worked.
There are a few things missing here:
If you want your class to be accessible outside of your module, you have to export it:
export class Test {
// ...
}
Browserify creates functions on top of the classes you define. So it won't be accessible globally (which is a good thing). Normally you would import it in another file and use it:
// in any TS file that wants to use `Test` class. Make sure this is included in the gulp entries as well
import {Test} from "test";
var t = new Test();
console.log(t);
Or if really want it to be accessible globally, you can attach it to window object:
// In Test.ts file:
(window as any).Test = Test; // This can be useful when debuging. But don't do this in production code.
EDIT : This was answered pretty quickly by someone pointing to something obvious in the rewire documentation. Note that I wrapped my modules in IIFEs because I was trying to get node to stop complaining about block scoped declarations outside of strict mode. Instead of using IIFEs (with strict mode), the easier way is just to use the --use-strict flag on your node command:
node --use-strict app.js
that way you can use ES6 in your code as normal and they will still be accessible by rewire. Hooray!
I am trying to test my node ES6 application. More specifically, I am trying to test a function in a module that isn't exported from a module. Currently, I cannot even get that function to be defined in my test. I am trying to use rewire to test this.
I'm not sure if this might a problem with strict mode or using ES6, but I cannot seem to find any hints to solutions online :(
Any help would be appreciated!
Here is my module:
//myModule.js
(function(){
'use strict';
let myFunction = () => {
return 'hello';
};
})();
And here is my test:
//myModule.spec.js
(function(){
'use strict';
let rewire = require('rewire');
let myModule = rewire('./myModule.js');
describe('app', () => {
it('should do something', () => {
let func = myModule.__get__('myFunction');
expect(func).toBeDefined();
});
});
})();
And this is the output I get from running jasmine-node on the directory:
Failures:
1) app should do something
Message:
ReferenceError: myFunction is not defined
Stacktrace:
ReferenceError: myFunction is not defined
Those IIFE's you're wrapping your code with are causing the problem. It's even mentioned in the fine manual:
Variables inside functions can not be changed by rewire
I have read the details on NodeJS site : https://nodejs.org/api/modules.html. I don't understand how modules work, and what are the minimal steps for creating a module, and how npm can help me.
How can I create a module?
How do I use a module?
What does putting it on npm mean?
Note: this is a self answered question, with the purpose of sharing knowledge as a canonical.
You can create a NodeJS module using one line of code:
//mymodule.js
module.exports = 3;
Then you can load the module, by using require:
//app.js
require('./mymodule.js')
I added './' because it is a module of one file. We will cover it later.
Now if you do for example:
var mymodule = require('./mymodule.js');
console.log(mymodule); // 3
You can replace the number 3, with a function, for example:
//mymodule.js:
module.exports = function () {
console.log('function inside the module');
};
Then you can use it:
var mymodule = require('./mymodule.js');
mymodule();
Private variables:
Every variable you define inside A module will be defined only inside it:
//mymodule.js
var myPrivateVariable = 3;
publicVariable = 5; // Never user global variables in modules
//It's bad-pracrtice. Always add: var.
module.exports = function() {
// Every function of the module can use the private variables
return myPrivateVariable++
};
//app.js
var mymodule = require('./mymodule.js');
console.log(mymodule()); // return 3
console.log(mymodule()); // return 4
Reuse modules:
One more thing you need to know about NodeJS modules, is that if you use the same module twice(require it), it will return the same instance, it will not run in twice.
for example:
//app.js
var mymodule1 = require('./mymodule.js');
var mymodule2 = require('./mymodule.js');
console.log(mymodule1()); //return 3
console.log(mymodule2()); //return 4 (not 3)
console.log(mymodule1()); //return 5
As you see in the example below, that private variable is shared between all the instances of the module.
A module package
If your module contain more than one file, or you want to share the module with others, you have to create the module in separate folder, and create a package.json file for the module.
npm init will create package.json file for you.
For modules, there are 3 required parts:
package.json
{
"name" : "You module name",
"version" : "0.0.3"
}
Now, you can publish the module, using npm publish. I recommend you publish all your modules to github as well, then the module will be connected to your github page.
What you publish to NPM will be accessible by everyone. So never publish modules that contain private data. For that you can use private npm modules.
Next steps
Modules can return more than one function or one variable. See this samples in which we return an object.
module.exports.a = function() {
// ..
};
module.exports.b = function() {
// ..
};
// OR
myObj = {
a:3,
b:function() {
return this.a;
}
};
module.exports = myObj;
More info:
Read about package.json files
Versioning in you modules best practice
More best practive for NodeJS modules
Private modules, using private npm
Related Questions:
What is the purpose of Node.js module.exports and how do you use it?
module.exports vs exports in Node.js
Creating module in node.js is pretty simple!!!
You may consider module as a set of functionalities you can use in other code by simply just requiring it.
for eg:Consider a file functional.js having the content:
function display(){
console.log('i am in a display function');
}
module.exports = display;
Now just require it in any other module like:
var display = require('./functional');
display()
Output:i am in a display function
Similarly you can do:
var exports = module.exports = {};
exports.display = function(){
console.log('i am in the display function');
}
or you do the same for objects like:
var funObj = {
hello:function(){
console.log('hello function');
},
display:function(){
console.log('display function');
}
};
module.exports = funObj;
There are two main ways for wiring modules. One of them is using hard coded dependencies, explicitly loading one module into another using a require call. The other method is to use a dependency injection pattern, where we pass the components as a parameter or we have a global container (known as IoC, or Inversion of Control container), which centralizes the management of the modules.
We can allow Node.js to manage the modules life cycle by using hard coded module loading. It organizes your packages in an intuitive way, which makes understanding and debugging easy.
Dependency Injection is rarely used in a Node.js environment, although it is a useful concept. The DI pattern can result in an improved decoupling of the modules. Instead of explicitly defining dependencies for a module, they are received from the outside. Therefore they can be easily replaced with modules having the same interfaces.
Let’s see an example for DI modules using the factory pattern:
class Car {
constructor (options) {
this.engine = options.engine
}
start () {
this.engine.start()
}
}
function create (options) {
return new Car(options)
}
module.exports = create