What is cnpm? How to use it? - node.js

I have recently come across a project that extensively uses cnpm for package managing. I saw something like
var a = require(#renil/a);
I have never seen something like this(#) in node when requiring a module.
Can anybody help me out

Those are actually two unrelated things. cnpm I had not heard of until I saw your question. After googling, it appears to be a Chinese maintained registry of node modules. Not sure what else is different but I'd probably stay away from it unless you know you need it.
The # symbol in a package name has to do with scoping related modules. That's well covered in the npm docs: https://docs.npmjs.com/misc/scope

These are scoped npm packages:
All npm packages have a name. Some package names also have a scope. A scope follows the usual rules for package names (url-safe characters, no leading dots or underscores). When used in package names, preceded by an #-symbol and followed by a slash, e.g.
#somescope/somepackagename
Scopes are a way of grouping related packages together, and also affect a few things about the way npm treats the package.

Related

Is there any difference on how to declare a ClojureScript dependency on shadow-cljs.edn file?

I have been working on a Clojure/ClojureScript project and something intrigues me.
On the shadow-cljs.edn file, there is a declaration of the
dependencies. As you might see below, some of them have "a full name"
declaration, indicated as username/repository-name. An example is
venantius/accountant.
Others are declared only as repository-name, such as [bidi "2.1.5"] which is actually published by juxt user (source).
I am afraid this could be problematic since multiple users could create repositories with the same name:
{:source-paths ["src" "dev" "test"]
:dependencies [
;; for deploy w lein deps below need to be in project.cljs
;; third-party dependencies
[venantius/accountant "0.2.5"]
[bidi "2.1.5"]
[cljs-hash "0.0.2"]
[clova "0.46.0"]
[com.andrewmcveigh/cljs-time "0.5.2"]
[org.clojure/core.match "1.0.0"]
[binaryage/dirac "RELEASE"]
[com.pupeno/free-form "0.6.0"]
[garden "1.3.10"]
[hickory "0.7.1"]
[metosin/malli "0.8.4"]
[medley "1.4.0"]
[binaryage/oops "0.7.0"]
[djblue/portal "0.16.1"]
[djblue/portal "0.18.0"]
[proto-repl "0.3.1"]
[reagent "1.1.0"]
[re-frame "1.2.0"]
[district0x/re-frame-window-fx "1.1.0"]
[cljsjs/react-beautiful-dnd "12.2.0-2"]
I am not sure how the low-level of dependency installation goes in a Clojure/ClojureScript project.
Is it a bad practice to have only the brief name of dependency? Is an ambiguity problem feasible or even possible?
Until not too long ago it was allowed to publish dependencies to https://clojars.org without a group name. In those cases the group would become identical to the artifact id. So bidi is effectively bidi/bidi.
Nowadays, new packages may only be published with a specific group name. However, old packages may continue using their older name.
The names used to publish also do not need to match their github repo coordinates. These are separate systems. They often match but are not required to.
To anwer your question: You should avoid using the same dependency multiple times. And you should use the official published name for each library. Some libraries are still updated using their old identifiers. Some moved to the newer longer names, while the old ones are still available but no longer receiving updates. Always consult the documentation of the specific libs to be sure which one you are supposed to use. They'll usually have some kind of info in their READMEs.
Conflicts may happen if you get the "same" lib via different identifiers. These may be very difficult to identify, when you run into trouble. This is true for any dependency resolver your use (eg. project.clj, deps.edn, shadow-cljs.edn). Best practice is to keep your dependencies as clean as possible.

How to use certain node module

My goal is to read in graphml files and retreive information about the fields that are contained within the nodes.
I have found a node module that seems to do just that so I decided I'd give it a try before writing my own code.
Unfortunately I the documentation is pretty poor and I have only been using node.js for about three months so I cannot figure out what the few clues given mean.
Global Install
npm install -g graphml-schema-generator
To have the wizard assist you with questions, type: gschema And answer the questions until finished.
Alternatively, you can use the following syntax: gschema path/to/graphml/file path/to/out/directory The paths can be either relative or absolute. The tool should pick on it either way.
Local Install
npm install --save graphm-schema-generator
You can either type the whole path to the file each time, such as: ./node_modules/gml-to-typescript/build/index Or you can create an npm script that references the path
However you choose to go about it, the usage is exactly the same as stated in the Global Install section. Please refer to that.
If you don't want to pollute your development environment this might be a better way to install this. Then you can use npm scripts to alias it to a more manageable command.
There's no GitHub repository or what-so-ever. I have read through the code and basically there are three files of which two seem to be sourcefiles (exporting some modules that are used in the last one) and one that's called "app.ts".
I somehow expected that I could use this module like
import {<ModuleName>} from 'graphml-schema-generator';
or
require('./node_modules/graphml-schema-generator";
but this isn't the case. I do not understand what
gschema path/to/graphml/file path/to/out/directory
would mean or how it would be used. I guess there's some basic misunderstanding about packages on my side.
here's an Image of the modules hierarchy
So I want to understand how to use this module and if so, what I did wrong
Thanks in advance

TypeScript Import Confusion - It Can't Be This Hard

I have been working with TypeScript off and on for two years now. I am not an expert by any means, but I've spent some time in the eco-system: with VS2015 and node tools, with VSCode, and at the command line with tsc and typings (also used by VSCode).
And I have struggled with the correct way to get static typing and auto-complete etc in the code I've been writing.
I have a repo I maintain (EasyNodeQ) which was the start of my TypeScript experience and I sort of got that to a manageable place with ///reference and DefinitelyTyped. But any time I tried to use that within another project I had issues.
Things got a little better when I started using typings (rather than downloading the *.d.ts files myself) and especially with the ambient flag.
But I still have lots of issues trying to use that package within other projects. Depending on the approach I take, I get lots of Duplicate Identifier's, or module not found's or...
And this can range from Node definitions, to packages I use in both places (like node-uuid).
All I want to understand is this: how to I structure EasyNodeQ so that as I'm working on it, I get the static typings benefits of TypeScript but also have it be seamlessly included in other projects which can then also get these benefits?
Does that make sense?
The basic use cases are: npm install a package and get its typings, use my EasyNodeQ package and get its typings, work in a new project that uses EasyNodeQ and other packages and easily manage those typings.
Preferably in a VSCode or command line way...
This is with ES6 and the latest version of TypeScript (though an answer that works with ES5 would be nice - just not required).
I hope this makes sense. I've looked all over and I can't cobble together an answer that works.
UPDATE
I'm not convinced I've done this the "right" way, but it's working now so I thought I'd post the various things I've done (generally in the order I think they mattered and not inclusive because I may have forgotten some).
I hadn't npm'd the dependency package (easynodeq) and was just using a git url in the package.json - so I created a proper npm package and now install that package from npm
Instead of trying to use Bus.ts as both code and definition, I made Bus.js the "meat" of the npm, and built a Bus.d.ts file (also in the npm)
Embraced typings, using non-ambient definitions where possible and a mix of ambient definitions downloaded (via git) from DefinitelyTyped and "--ambient" definitions for the rest (because I'm still confused about the difference). The ambient definitions ended-up being the majority: node, express, serve-static, express-serve-static-core, mime, amqplib, when vs just bluebird and node-uuid, even though most of them were found by "typings search ..." Am I doing something wrong?
Modified package.json to also do "typings install"
Cleaned-up the git repo
There are several ways to make this work today. As you mentioned, using Typings works for definitions that aren't natively included in their NPM packages. For ones that do, you can using the typings field in package.json and it'll work with node module resolution. When you combine this together, you can publish packages that use both typings.json and relies on packaged typings - though this now forces your consumers to be using Typings to install the definitions. None of this, however, works with "ambient" definitions as they can not be namespaced properly.
This may be useful: https://github.com/typings/typings/blob/master/docs/faq.md#should-i-use-the-typings-field-in-packagejson. There's also dozens of examples I have using both workflows: https://github.com/blakeembrey/change-case/blob/master/package.json#L6 which uses node module resolution all the way down and https://github.com/blakeembrey/popsicle/blob/master/typings.json which uses Typings instead. Using Typings is only possible because it works to create namespaced ambient modules for you, but they won't conflict.

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 .

npm package.json OS specific dependency

Is there a way to specify OS specific dependencies in a npm package.json file?
For example, I would only want to install 'dbus' (https://npmjs.org/package/dbus) as a dependency for my module if the user is running Linux. I would have a different dependency for Mac and Windows.
There's a possible good way of doing this, depending on your setup.
npm package.json supports an os key,
and also optionalDependencies
os can be used to specify which OS a module can be installed on.
optionalDependencies are module dependencies that if they cannot be installed, npm skips them and continues installing.
In this way you can have your module have an optional dependency for each OS, and only the one which works will be loaded/installed ^.^
EDIT: As #Sebastien mentions below, this approach is dangerous.
For any given OS, at least one of your dependencies is "required" and the rest "optional". Making all versions of the dependency optional means that if your installation fails for a legitimate reason, it will silently skip installation and you will be missing a dependency you really need.
I think the short answer is no. I can think of a couple of workarounds though - the simplest is to just add everything to package.json regardless of OS, and then require() the correct one at runtime.
If that doesn't work for you, you might be able to use an install script to get the result you're going for - https://docs.npmjs.com/misc/scripts
I haven't tested this but I think it would work:
Add something like this to your package.json:
,"scripts": {
"install": "node install_dependencies.js"
}
And then add a install_dependencies.js file that checks the OS and runs the appropriate npm install ... commands.
There's also the bindings-shyp module:
https://www.npmjs.com/package/bindings-shyp
Helper module for loading your native module's .node file
This is a helper module for authors of Node.js native addon modules. It is basically the "swiss army knife" of require()ing your native module's .node file.
Throughout the course of Node's native addon history, addons have ended up being compiled in a variety of different places, depending on which build tool and which version of node was used. To make matters worse, now the gyp build tool can produce either a Release or Debug build, each being built into different locations.
This module checks all the possible locations that a native addon would be built at, and returns the first one that loads successfully.
Quoting #npm_support at:
https://twitter.com/npm_support/status/968195526989512705
2/2 If you'd like to avoid installation problems related to dependencies, one route is for you to write a wrapper that's required as a regular dependency, and to make sure that it has optionalDeps (and also ensure that the wrapper verifies you have everything needed to work).
But IMHO it looks more like a workaround than solving the problem for real.
I can understand that npm wants to preserve portability and avoid to deal with platform specifics, but it has to be done anyway and IMHO doing this at runtime is not optimal (specialty if one wants do optimize code size).
So today I have no optimal solution to share but an open discussion for proposal.
Can't "conditional dependencies" be supported in npm ?
The 1st thing that came to my mind was to to add a "override" section that will change (+add, -remove, =replace) current parsed sections.
For example:
dependencies: { "common-stuff": "*" }
overrides: {
"os: { linux: { dependencies: { "+best-linux-module" } } }
}
And other option suggested by a developer I know, would be to introduce a provides keyword, then several modules could provide a same semantic than would be satisfied by resolver (a la debian), but it's generating similar overhead.
I am looking for a generic approach not only focused on OS support but also on other flavors of package (depending on engines for instance).
Do you know any related issue in NPM tracker ? if not I am considering to file a bug to be tracked at:
https://github.com/npm/npm/issues?q=dependencies+conditional
Feedback welcome on this idea.

Resources