I have a Node.js project that I want to compile with Closure Compiler. I do not want it to run in the browser/use browserify. I mainly want the utility of type checking. I originally got the compiler to work correctly using the following:
java -jar compiler.jar -W VERBOSE
--language_in ECMASCRIPT5_STRICT
--externs closure-externs.js
--js="lib/**.js"
Where closure-externs.js manually defined variables and functions which I was using from Node.js in a rather crude way:
// closure-externs.js
/** #constructor */function Buffer(something){}
function require(path){}
var process = {};
[...]
It turns out that this worked only through sheer luck. There is no dependency tracking between files, so you can have cases where you return a type {Foo} and the compiler will complain that it doesn't exist (depending on the machine, depending on the compile order). I then found out I was doing it all wrong and should be using --process_common_js_modules so the compiler will do dependency tracking where I require("foo"). I am currently invoking the compiler like so:
java -jar compiler.jar -W VERBOSE
--language_in ECMASCRIPT5_STRICT
--externs externs/fs.js
--js="lib/**.js"
--process_common_js_modules
--common_js_entry_module app.js
But this is failing with:
ERROR - required entry point "module$crypto" never provided
ERROR - required entry point "module$dgram" never provided
ERROR - required entry point "module$extend" never provided
ERROR - required entry point "module$fs" never provided
ERROR - required entry point "module$net" never provided
ERROR - required entry point "module$q" never provided
Some of these modules are native to Node.js (e.g. fs) whereas others are contained in node_modules like q. I don't want to run these external modules through the compiler, so I know I need to set up externs file(s) for them. I know there is https://github.com/dcodeIO/node.js-closure-compiler-externs for common Node.js externs, and I know how to invoke them on the compiler, but for some reason when I do something like --externs externs/fs.js the error for module$fs remains. What am I doing wrong?
I know there's other flags like --module and --common_js_module_path_prefix but I'm not sure if I need to use them to get this to work or not. My Google-fu has failed to come up with any answers on the correct incantation here. :(
The issue is that you wish for the compiler to somehow recognize that certain require calls are internal, namely that the required module should be processed by the compiler as source, and others are external so should be left alone. There isn't a good way to handle this situation currently.
Workarounds
Use Post-processing to Add External Require Statements
In this scenario you would completely omit any require statements to external modules. The compiler would only process code with internal require statements and modules. After compilation, you would prepend the external require statements:
Header JS To Be Prepended
var crypto = require('crypto');
Source To Be Compiled
console.log(crypto);
Because crypto is declared in an extern, the compiler will correctly recognize the type and symbol name.
Alias Require Calls
When the --process_common_js_modules is specified, the compiler recognizes require statements and expands them in a similar fashion to the way macros work in other languages. By aliasing the require statements that should remain external, the compiler will not recognize them and thus not expand them.
Source To Be Compiled
var externalRequire = require;
/** #suppress {duplicate} this is already defined in externs */
var crypto = externalRequire('crypto');
console.log(crypto)
If you're using the Closure Compiler only for type-checking—i.e., with the --checks-only option—there is another workaround which has the advantage (over the ones mentioned in Chad's answer) of working correctly with unmodified third-party NPM modules which in turn import built-in modules.
Using Stubs
The trick is to create stub NPM modules to stand in for the built-in ones. These can be minimal; they only need to declare the parts of the API you're actually using.
Here's an example for the path built-in module.
In externs/path/path.js I have the "externs" declarations (not actually externs, so e.g. you can't use #nosideeffects) for the part of path that I need:
/** #const */
var path = {};
/**
* #param {string} path
* #return {string}
*/
path.dirname = function(path) {};
/**
* #param {string} path
* #return {string}
*/
path.extname = function(path) {};
/**
* #param {...string} var_args
* #return {string}
*/
path.join = function(var_args) {};
module.exports = path;
In externs/path/package.json, I have a minimal NPM package config:
{
"description": "Fake package.json for require('path')",
"main": "path.js",
"name": "path",
}
Then create a symlink from node_modules/path to externs/path, and add the following to my compiler flags:
node_modules/path/package.json
node_modules/path/path.js
(You could put the stub implementation directly in to node_modules but I prefer to keep my stubs separate from the real modules managed by npm. I just need to remember to manually add the symlinks to my Git repo, because it's otherwise configured to ignore node_modules.)
Related
I'm trying to minimally use TypeScript types in my JS projects so that IntelliSence can provide better completions and I get warnings about type-related problems.
I added a jsconfig.json file that sets up the typechecking in JS, and I mostly use JSDoc to describe the types. This works pretty well.
Now I'd like to create some types that I use throughout my project. I tried using types.d.ts but that seems to be something React-specific and isn't documented.
I also tried putting the types in an index.d.ts file, but that only gets read when you're importing from the index and so it won't be useful for the components that implement what is exported from the index.
/// <reference types="." /> also doesn't import the index.d.ts types into the current scope. I resorted to doing /** #typedef {import('.').Foo} Foo */ for each type I'm using in the current file.
Is there a minimal and maintainable way to manage types in typescript but write the rest in javascript?
If the code in js file is:
const a = prompt();
the code will be
/** #type {number} */
const a = prompt();
Write JSDoc to .js file.
i am new to javascript and typescript,and i install mysql module usingnpm install mysql
and i found that the intellisense of vscode can automatically recognize the type even when i'm using javascript
just like this
and the module source file doesn't contain any .ts file,i wonder how it work.
Code downloads TS typings in the background. It checks package.json or imports to decide which typings to get. The typing for mysql:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/8f158d2d4c8459463e5e0a27cc298041483c5e22/types/mysql/index.d.ts
For more info follow the link bellow:
https://code.visualstudio.com/docs/nodejs/working-with-javascript
The mysql package is written in pure JS, however it includes documentation. This documentation is standardized as JSDoc. VSCode has built in support for reading this documentation and displaying it to the user. (Note: it does not support all JSDoc tags)
Example from mysql/index.js. (source)
/**
* Create a new Connection instance.
* #param {object|string} config Configuration or connection string for new MySQL connection
* #return {Connection} A new MySQL connection
* #public
*/
exports.createConnection = function createConnection(config) {
var Connection = loadClass('Connection');
var ConnectionConfig = loadClass('ConnectionConfig');
return new Connection({config: new ConnectionConfig(config)});
};
The #param tag specifies what types config can receive. {object|string} means it can either be an object or a string.
I am new to webpack and node, and I am wondering how to use the
__non_webpack_require__
function. I've visited webpack's website but am still confused as to what this function is and how I can use it. Could you provide a short description of a use case for this function and then how to use it in a node / react app?
Webpack processes every module that you use in your application starting from the entry point(s) and including every module you import (import or require) and includes it in your bundle. The __non_webpack_require__ is a function that will result in a plain require call.
Let's take this entry point as an example:
const processedByWebpack = require("./module");
const notProcessed = __non_webpack_require__("./non-webpack");
console.log(processedByWebpack);
console.log(notProcessed);
In this case webpack will bundle that application and include every module you import, which in this case is only the ./module.js. So the output will be:
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
const processedByWebpack = __webpack_require__(1);
const notProcessed = require("./non-webpack");
console.log(processedByWebpack);
console.log(notProcessed);
/***/ }),
/* 1 */
/***/ (function(module, exports) {
module.exports = "This module is bundled with webpack"
/***/ })
/******/ ]);
The ./module.js module was included in the bundle and would also have been processed by any loaders if there were any applicable rules present. On the other hand, the ./non-webpack.js is not included in the bundle and webpack made it a call to require. This means that the ./non-webpack.js will be resolved when it's executed and it will fail with a runtime error if it isn't available or contains invalid JavaScript.
__non_webpack_require__ is a way to work around the fact that webpack processes all require calls. Because webpack bundles up all the modules, it must know which modules to include at compile time. This makes require more restrictive than it actually is in Node.js. For instance, you can't use dynamic requires, that means you can't use a variable as the module's path (see also webpack dynamic module loader by require). For example:
// Path to module as a variable (could be an argument to a function)
const modulePath = "./module";
const processedByWebpack = require(modulePath); // Fails
const notProcessed = __non_webpack_require__(modulePath);
In the regular require webpack will fail, because it doesn't know which modules to include to cover all the modules that could be referenced at runtime. In this example it might seem obvious, but it could go as far as using user input to determine the module to load. With __non_webpack_require__ it simply creates a require call and you'll have to deal with possible Module not found exceptions at runtime.
When should you use it?
Probably never. That's one of these functions that should be considered as last resort where you need to sidestep webpack to have some dynamic module resolution. In most situations there are other solutions to achieve the same goal (e.g. deferring imports to runtime by using Externals), everything else is an edge case.
You will have noticed that __non_webpack_require__ is transformed into a require call. This means that it only works in Node.js and fails in any browser environment unless you have a global require defined that may or may not do something special. Another downside is that it is webpack specific and when you want to use another tool (for instance for testing), it won't work or you'll have a hard time trying to work around it.
I just started a new NodeJS application in PhpStorm which uses some external packages. Unfortunately I see a lot of Unresolved variable or Unresolved function or method warnings:
Obviously this is very distracting. Can I somehow manually tell the IDE to load some definition files of the external packages I use (e.g. mongoose in this example)?
If I find no other solution I'd simply disable those inspections which is kind of a bad "fallback" since they usually provide some good hints for typos etc.
Solution:
I had 2 different node_modules directories in my project:
project\client\node_modules\...
project\server\node_modules\...
Both were marked as excluded. I simply removed the excluded mark (right-click on the folder in the project tree). PhpStorm shows correct auto completion now and the Unresolved warnings are gone.
If you have jetbrains suite, It's better to use webstorm for nodejs application.
However, if you want to keep phpstorm. You can use a jshint module for global variables declaration, and use jsdoc for variable instance :
/**
* Description
* #type {Schema}
* #property {object} methods
*/
var Schema;
-- EDIT --
Have you set up your phpstorm as the jetbrains doc ?
Work on nodejs with phpstorm
I do own quite a big code basis implemented in JavaScript based on NodeJS. I do want to give typescript a try and want to implement all new modules in typescript. Just to see how it performs and how I like the idea. I do need to be able to revert back at any time so I do not want to put to much effort into the migration.
I started by using WebStorm and Gulp to support typescript. I created a new module and used the import / require combination.
import settings = require("./settings");
import _ = require("lodash-node");
By doing so I receive a couple of errors.
Error:(22, 27) TS2307: Cannot find external module './settings'.
Error:(23, 20) TS2307: Cannot find external module 'lodash-node'.
Those modules have no typescript definition file and are plain javascript modules (lodash is obviously a external library). I do have a couple of dependencies and I do not want to create definitions manually even if they are just empty stubs. As mentioned I do want to keep the integration as simple as possible.
Is there a general flag or something like that I can set?
The easiest way to proceed (if you don't want type information for a module) is to write:
declare module "lodash-node" {
var notTyped: any; // naming is unimportant here
export = notTyped;
}
Put that in a separate .d.ts file and /// <reference> it. Then _ will be of type any in your implementation file and the compiler won't complain about not know what module you're talking about.
You can use webpack's typescript-loader and start from there. Make sure you put target: 'node' on your webpack config so you don't have all the browser junk.