NodeJS NPM modules; how do I make it "just work?"

I just purchased WebStorm because of my awesome experience with ReSharper. ReSharper was magical at being able to intelligently resolve symbols in JavaScript. I am creating a new NodeJS package and trying to use WebStorm as the IDE. To my utter surprise and extreme frustration, WebStorm seems really dumb when it comes to modules.

In my package.json, I have defined some dependencies and devDependencies. These install with "npm install" just fine. I was able to get Mocha tests to run, and "require('chai')" resolves as expected. However, WebStorm does not recognize symbols pulled in with require!

What I've done:

1. Added the "Node.js ... Core Modules" library and "Node.js Globals" libraries. That got "require" to finally resolve.
2. Created a library called "Node.js Dependencies for myproject." It points to my root node_modules folder.
3. Ensured that these are checked in the "Use JavaScript Library" list.

Despite this, for code like this:

var expect = require('chai').expect;


I get the error:

"Unresolved variable expect."

How the heck do I get WebStorm to work with basic Node packaging? I know some big fans of WebStorm that do Node development, so surely there's got to be a non-annoying way to make this work.
10 comments

Interesting problem that I've been struggling with as well: I have similar issues with the two npm modules lodash and async.

The problem stems from the flexibility of the require system used to define modules in node. What's exported from a node JS module is whatever's assigned to module.exports, and there are an infinity of increasingly obscure ways to do that assignment. I don't think it's reasonable to expect WebStorm to work out the answers every time through static analysis (no, I'm not related to JetBrains ;-)). What I would like is some way to tell the IDE what the interface to a module actually is: anyone know if there is anything like that?

- Dave

P.S. I took a look at the chai module: it is a great example of the problem. Here is an abbreviated view of the code that assigns module.exports.expect in chai.js to the anonymous "function(val, message).." from expect.js. It took me a while to work out how it does this: I don't see how static analysis in an IDE could ever work this out in general.

In the main chai.js, we have

...
var used = []
  , exports = module.exports = {};
...
exports.use = function (fn) {
  if (!~used.indexOf(fn)) {
    fn(this, util);
    used.push(fn);
  }

  return this;
};
...

var expect = require ( './chai/interface/expect' );

exports.use(expect);
...

And in the required interface/expect.js, we find

module.exports = function(chai, util) {
  chai.expect = function (val, message) {
    return new chai.Assertion(val, message);
  };
};


0

Hello!

the possible workaround is using the typescript stubs (configured as javascript libraries) for type resolving. See http://youtrack.jetbrains.com/issue/WEB-6667 for more information.

0

Hey,

that's pretty cool. (makes mental note: must read the release notes...).

Works perfectly for async, but not for lodash (for me, at any rate):

var _ = require('lodash');
_.lastIndexOf([3], 3); // Wrongly flagged as "Unresolved"

Oddly, it correctly suggested the signature of lastIndexOf while I was typing, but then got it wrong after I'd finished. Which seems quite odd - any more ideas?

- Dave

0

Works for me - see the attached screenshot...



Attachment(s):
lodash.png
0

Auto suggest while typing works for me too: I tried to say that before, but I wasn't clear enough.

What doesn't work is that after you finish typing, you get an "Unresolved function" marker, which in my setup is an underlined function and one of those little warning markers at the right hand side - see my screen shot ;).

I'm probably a bit obsessive about this stuff, but I tend to rely on these warnings a lot and to try and keep that right hand column clear.

- Dave



Attachment(s):
Screenshot from 2013-12-04 10:41:25.png
0

I understood you right. The function is not only suggested by completion, it's correctly resolved for me, and my screenshot shows the definitions suggested when I hit Ctrl+B on _.lastIndexOf()...

0

some other code in your project may affect the type hinting, causing the function to not being resolved...

0

OK, I did some more digging: I think the difference between our environments is that I actually have the lodash npm module installed!

I can make my screen look like yours by deleting or excluding the  node_modules/lodash directory. This has the (reasonable) side effect of  giving me a warning on the line "require('lodash')" - I see from your  screenshot that you have the same warning currently.

I think that if you install the lodash npm module in your project, your screen will look like mine.

Given all this, any more ideas on how to get no warnings?

- Dave

P.S. Thanks for sticking with this - I appreciate it.



Attachment(s):
Screenshot from 2013-12-04 12:15:23.png
0

Yes, I've recreated the problem after adding lodash module to the project

See http://youtrack.jetbrains.com/issue/WEB-6667#comment=27-574426 for a different workaround - does it work for you?

I've added a comment regarding this problem to http://youtrack.jetbrains.com/issue/WEB-6667

0

That's fascinating. I just read the lodash source to understand why that works, which is quite a trip. During that excursion I found that I can achieve the same end with

var _ = require('lodash')._;

This works better for me (it doesn't show all the internal garbage options that Petr Kokorev noted in that post, and seems clearer), although in an environment without some other "_" this would have a warning on the require line.

If the original poster to this thread is still here, note that chai has exactly the same problems as lodash, but not the same workaround. I'm beginning to suspect that the TypeScript solution in general has this limitation.

Anyhow, I have a decent environment now, so thank for the help Elena.

- Dave

0

Please sign in to leave a comment.