`require` in VSCode extension: Cannot find module './tool.js' - node.js

I'm trying to write a language server based off of the vscode languages server sample.
I have a file at lsp-sample/server/src/tool.js which was generated by an external tool (js_of_ocaml), which I'd like to import in my plugin using require. I do this as follows in lsp-sample/server/src/server.ts:
var tool = require('./tool.js');
However, when I do so, I get the following rutime error:
Cannot find module './tool.js'
If I require using an absolute path, I don't get an error, but obviously that doesn't work for an extension that I'd like to run on multiple computers.
What is the proper path I should be giving to require? What is the "current directory" that I need to define my relative path in relation to?

When using require(), you should not include the file extension. Try
var tool = require('./tool');
instead.

Related

Cannot Import Module without explicit file extension after switching from CommonJS to ESM [duplicate]

I'm trying to get a handle on Node and ES modules. Specifically how/if you can omit the file extension from the path string value of the import statement (and optionally get VSCode to autocomplete those paths).
I understand you can either gives files the .mjs extension or set "type" = "modules" in the package.json but both approaches lead to the following problems.
VSCode won't autocomplete the path if the file extension is .mjs, it only sees the file if it's .js. However if it is .js the autocomplete omits the extension from the string and the import fails until I add it manually.
Trying to use a library like graphql inside my own modules also fails because all the import statements between the .mjs files in the graphql module have been written omitting the extension from the string.
SO... when is not including the extension valid with ES6 module imports, and is there anyway to get this condition enabled with NodeJS?
The node.js ES6 module implementation specifically does not do automatic file extension resolution as documented in https://nodejs.org/api/esm.html#esm_customizing_esm_specifier_resolution_algorithm :
The current specifier resolution does not support all default behavior of the CommonJS loader. One of the behavior differences is automatic resolution of file extensions and the ability to import directories that have an index file.
However this can be changed by a command line argument --experimental-specifier-resolution=[mode]
As such not giving a file extension is invalid by default but can be made valid depending on how you run node.js.
However, there are systems implemented before the ES6 spec was written that implements ES6-like import syntax such as Typescript and Babel. These systems assumed you can exclude file extensions in your imports. If you are using such a system to compile your ES6 imports to ES5 syntax you can exclude file extensions, sometimes, depending on if the version of the compiler you are using supports it.

What is the proper way to point my module to a config directory using config.js?

I built a node module for others to import into their node projects. I use config.js. I'm having issues telling their scripts where to look for my config directory is.
I'm using this code to define it within my module, but its doesn't cover all possible scenarios.
var config_dir = path.dirname(process.mainModule.filename)+path.sep+'node_modules'+path.sep+'open-payments'+path.sep+'config';
process.env.NODE_CONFIG_DIR=config_dir
I need something that will tell my module where to look regardless of what or where the script is that's using my module.
You can use __dirname to get the full path for the current executing script (i.e. not necessarily the one that was called with node, but the one where __dirname was queried).
See this question for more details: How to get path to current script with node.js?

Import a javascript module as dynamic using typescript

I want to import a normal javascript module (e.g. vhost) into my node.js typescript file using CommonJS.
I can do this with the following line:
import vhost = require('vhost')
We assume that I can't find a .d.ts file on the internet, but I also don't want to write it by myself, so I just use the vhost variable without intellisense.
The compiler complains and complains:
How can I tell that I just want it to be 'dynamic' (like the C# dynamic keyword or 'var' in normal javascript) and use all of the things in the picture above?
I could create a vhost.d.ts file, but I don't know what to write in there:
declare module 'vash' {
// what to write here?
}
I found this out while typing the question, it was so easy that it is almost embarrassing, but maybe somebody has this problem too.
Just use var instead of import:

Use __dirname into class compiled in Typescript AMD

I'm looking for a solution to use __dirname (or equivalent) inside a TypeScript class compiled in AMD, __dirname doesn't exists there. And because it's typescript, I can't (or I don't know how) import module that contains uri, allowing me to get the uri.
I found the solution once, but I don't remember how and I can't find it again so far.
I took a look to this, but it's in pure javascript and I use typescript, I tried to import module, but I get a TS error.
https://stackoverflow.com/questions/9027429/how-to-use-nodejs-global-module-objects-in-requirejs-modules
One solution is to:
In app.js, create a global var:
__basePath = __dirname;
Then, in the AMD script, use __basepath + 'relativePathFromBasePath' to load the file.
I know I found another solution but I cannot remember how.
I do not use TypeScript, but on the basis of the TypeScript code I've seen and on the basis of what I know of RequireJS, I believe you should be able to access module.uri like this:
import module = require("module");
console.log(module.uri);
The name module is special. You could also use require.toUrl(<module name>) (that's Url as in URL whereas the variable above is uri as in URI) but it does not seem as useful as module.uri for this task. For one thing you'd have to include the module's name in the call.
module.uri may contain .., so it needs cleaning up. I understand your code to be running server-side, so in Node.js we'd call path.dirname(path.normalize(module.uri)).

Mixing typescript definition files with nodejs require over multiple files in an internal module

Are there any known issues with mixing nodejs modules (require) with typescript definition files (d.ts) multiple times over files within a module?
My scenario is that I have a module namespace per folder (much like I would in C#), then I basically compile them all via tsc to an outputted my-module.js. However I keep getting really odd errors like Could not find type HTMLElement but lots of people have pointed out that tsc includes the typescript lib file by default which contains all those types.
I have noticed a few people having odd errors when they are including the same d.ts files over multiple files which are all compiled with the --out flag to get it all into one file, so could this be causing my issues?
An example of my usage would be:
///<reference path="path/to/knockout.d.ts" />
import ko = require("knockout");
This would then be put in each file which requires knockout js, which is at least 10 files in the module i'm trying to compile currently. It just bombs out constantly saying knockout.d.ts cannot find the type HTMLElemet, Element, Document etc.
If you are using external modules (which you are if you have a top level "import" - as shown above), then you can't use the --out switch to combine multiple source files. It is a limitation that with external modules that one source file = one module. With source that is not in an external module (i.e. contributes to the 'global' scope), you can combine input source to one output JavaScript file using --out.
I have no idea about the "could not find HTMLElement" issues. If you can provide a repro (and outline which version you are using) I can take a look.

Resources