Intellij IDEA resolve local require() path [ node.js ] - node.js

I'm trying to avoid relative require() calls in my express setup. I'd also like to avoid placing my code in the node_modules folder. In short, I'm trying to implement any of the methods described in this gist.
Any of those solutions will work fine for executing code with node or npm. However, I'm trying to find a solution that will also be supported by Intellij IDEA's code resolver, i.e. trying to make sure "go to declaration" and autocomplete hinting works.
I've tried the following
Setting NODE_PATH in the run configuration.
Using a global prefix, i.e. require( global.__base + "mylib").
Adding a symlinked folder to node_modules/.
Adding a symlink from a lib/ folder to node_modules/lib/ does work, but comes with two caveats:
Changes to the source files aren't picked up automatically, so I have to manually "synchronize" node_modules/lib, and
When "going to declaration", IntelliJ (of course) opens node_modules/lib/mylib instead of lib/mylib. This can lead to confusion as the actual file and the symlinked file can be open in separate windows.
Instead of a different way to require local paths (all these methods do work with node after all), I'd be happy with a way to hint to IDEA that it should search the lib/ folder for sources.

So, I realised that if you add a library through Project Structure > Libraries, it won't actually be enabled.
Instead, go to Preferences > Languages & Frameworks > Javascript > Libraries and add a new library. Set the framework type to node_modules, Visibility to Project and add your lib folder.
After adding it, make sure the Enabled checkbox is checked.
That's it, Intellij can now resolve your require('mylib') paths.
Use whatever method from the gist mentioned in the question to actually get node to resolve the paths.

Related

How can I make vscode assume a node.js context, so that it doesn't assume `fetch` exists?

By default, when editing a JavaScript file in VSCode, it will assume that the fetch function and related types exist in the current context. This makes sense for JavaScript designed to run in the browser, but when running on node.js the fetch function does not exist unless it is installed via node-fetch. I find that in this context, VSCode is misleading, as it will not highlight an error when you trying calling the fetch function, or access other types such as Request and Response, even though they do not exist unless you have node-fetch installed.
How can I configure vscode to assume a node.js context, and therefore assume that fetch does not exist unless I explicitly import it from node-fetch?
Why web types are there by default
From the docs for tsconfig.json compilerOptions.lib:
TypeScript includes a default set of type definitions for built-in JS APIs (like Math), as well as type definitions for things found in browser environments (like document).
How to change the defaults
Create a tsconfig.json or jsconfig.json, and set the compilerOptions.lib array to not contain "DOM", which means that lib.dom.d.ts (the "DOM standard library" type definitions file that comes with TypeScript) will not be assumed. You should specify which ECMA Script standard you want to write your source code in.
The config file also has fields to control what files it takes effect on: files, include, and exclude. If you specify none of them, include will default to **, which matches everything beside and recursively under subdirectories beside the config file.
Having to create this file could be seen as annoying if you just want to write a single JS file (ie. now you have a whole config file just for one source file!). I don't know if there are alternatives that are more convenient for such a use case. If anyone knows, please edit this answer.
I looked briefly into TypeScript triple-slash directives, which allow specifying things on a per-file basis, but I think you can only add things (ie. I don't think you can use them to remove a lib).
At the time of this writing, there are VS Code settings that can be applied at the user-settings scope that affect settings for implicit projects (JS/TS files which don't have a project config file) (js/ts.implicitProjectConfig.*), but none of them are for setting the compileOptions.lib field, and my gut says it's probably not going to happen (but don't quote me on that).
You probably also want types for the Node API
Use npm to install a version of #types/node. Make sure the major version number of the version you install matches the major version number of the version of Node JS you want to script to be runnable on.
Fun irrelevant facts to this question
Continuing on the point about VS Code's user-settings for implicit projects, VS Code puts some defaults in effect (on top of those that TypeScript itself does) if no project is detected. You can poke through the code at github.dev/microsoft/vscode by doing "Find in Files", using extensions/typescript-language-features/**/* as the "files to include" field, and compilerOptions as the find query. compilerOptions.lib seems to not be something that VS Code touches in such a scenario.

In typescript, how to restrict a typing reference to a certain file?

I'm trying to cleanly write some universal javascript code, for node and browser.
Most of the code is env-agnostic, however, some implementation parts detect the environment (node or browser) and conditionally execute different code.
I would like to activate node typings ONLY for those specific files. However, I couldn't find a way to do so. Either:
node typings, when referenced in even one file only, are made effective for all files (bad, since I could inadvertently rely on node specificities)
if not referencing node typings at all, typescript obviously complains about a lot of unknown definitions, which would be painful to patch by hand
Do anyone has a clean way of activating some type definitions for a selected set of files ?
It's not possible at this time.
A solution: building node-dependant and node-independant files separately. This could be done automatically with a script.

Spurious module ".." in Android Studio project

I followed the steps in How to share a single library source across multiple projects to add an external library to a project.
My project(s) structure:
Project MyTest1:
Module MyLib
Project MyTest2:
Module MyApp
I edited settings.gradle in MyTest2 and added , ..:MyTest1:MyLib to the include directive. Now, I am able to see and use the external library project from within MyTest2 project. Things work as expected.
However, I see a spurious module ".." alongside MyApp and MyLib. There are no nodes under it and it doesn't seem to cause any problems. I am wondering what exactly is this module for and if there is a way to get rid of it. Regards.
Edit
Both my projects are under a directory C:\MyDev. It appears that, anytime you bring up MyTest2 project, AS modifies a file MyTest2.idea\modules.xml and inserts the following line:
<module fileurl="file://C:/MyDev.iml" filepath="C:/MyDev.iml" />
It then complains that the module was not loaded and creates a fake ".." module. I think this is the root of the problem.
Do not declare ..:MyTest1:MyLib as your include. It will cause many problems. Instead, declare it the following way:
include ':MyLib'
project(':MyLib').projectDir = new File('../MyTest1/MyLib')

Referencing the Extension Java files between dependencies

Working on the new android side of extensions with the changes. I have my separate extension as its own dependency.
In my code I require references to the Extension.Java class as well as the HaxeObject.
These are located in extensions-api, which is it's own separate dependency.
I've tried including these files in my own dependency, this causes top-level exceptions because a number of the Java files were included twice. I've also tried not including the extensions-api, this works to some extent, however If in the future I decide to use more extensions this won't work (less than ideal).
I need to find a way to reference these files from one dependency to another. so from: MyExtension.src.org.haxe.nme.MyExtension and extension-api.src.org.haxe.nme.Extension
So I guess the point I'm stuck at is how I make these two dependencies see each other whilst compiling so that when they merge to make the .dex file they don't cause top-level exceptions.
I could potentially hack it by placing my extension into the extension-api folder. Something like:
<dependency name="extension-api" path="dependencies/MyExtension" if="android"/>
The issue with this being that the androidManifest merging wouldn't work.
I found the answer here:
the gist is in the project.properties file you want to add the line:
android.library.reference.1=../extensions-api
http://www.openfl.org/community/general-discussion/native-extensions/

Node.js/npm - dynamic service discovery in packages

I was wondering whether Node.js/npm include any kind of exension mechanism comparable to Python setuptools' "entry points".
So, in short:
is there any way I can do dynamic discovery of services provided by other packages using npm?
if not, what would be the best way to implement something similar? Specifying the extension name in the main module's configuration file seems to be the logical solution, but I wonder whether something "automatic" can be done.
I'm not aware of any builtin mechanism to do this.
One viable way of doing it yourself:
I made a small tool (Jumpstart) to quickly create project scaffolding from templates with placeholders, and I used a kind of plugin mechanism for that. It basically comes down to that the Jumpstart script searches for modules named jumpstart-* "adjacent" to where the module itself is installed. So it would work for both local and global installations. If installed locally, it would search the other local modules (on the same level) and if global, it searches the other global modules.
Note that here, "search" comes down to a simple fs.exists check to see if there's a Jumpstart template module with a particular name installed. However, nothing would stand in the way to actually get a full list of all installed packages matching the jumpstart-* pattern, and loading all at once. I could also search up the entire directory tree for node_modules directories and do the same. There's no point in doing this for this particular program, however.
See https://npmjs.org/package/jumpstart for docs.
The only limitation to this technique is that all modules must be named in a consistent fashion. Start with some string, end with some string, something like that. Any rogue packages polluting the namespace could be detected by doing further checks on a package contents: What files does it contain? What kind of object does its main module export? etc.
Brunch also uses a plugin mechanism. This one actually deals with file extensions, so is more relevant: https://github.com/brunch/brunch/wiki/Plugins . See for example source of the CoffeeScript plugin https://github.com/brunch/coffee-script-brunch/blob/master/src/index.coffee .

Resources