Best way to test global npm modules - javascript

Lets say I develop a global npm module called mytool that registers a env variable through "bin" in package.json with the name mytool.
So after I install it globally by typing
npm install mytool -g
then I can type mytool --someOption in terminal and handle the CLI input in javascript. Now lets assume that mytool works a lot with the current working directory of the CLI, so to just
node index.js --someOption
is a bad idea.
However to test for bugs I don't want to push a new version of "mytool" to npm and then install it globally from npm. Rather I want to be able to test this all locally.
Question: What is the best way to do test global npm modules without publishing to npm?

npm link
Contrary to what it seems, npm link can also be used in your case, too.
Just run it on the root folder of your project. No additional arguments are necessary.
Using it in you package folder will create a symlink in the global folder {prefix}/lib/node_modules/<package> that links to the package where the npm link command was executed.
It will also link any bins in the package to {prefix}/bin/{name}.

Related

How do I run npx commands without prefixing `npx`

For example when I run gulp I don't have to do npx gulp.
I can omit the npx and just run gulp
How do I do this for my own package?
I've added mycommand to the package npm bin config, but I still always have to do npx mycommand for it to work.
It depends on your operating system. On a UNIX-based OS (ie. Linux or Mac) you can use the alias command:
$ alias gulp="npx gulp"
For the rest of your terminal session, you can then run:
$ gulp
to run npx gulp. However, whenever you restart your terminal program, you'll lose the alias.
To make the alias permanent, you need to add the alias command to the appropriate start-up file (eg. .bashrc, .profile, etc.) for your OS. Simply copy/paste the exact command you used before, at the end of that file, save, and restart your terminal. You'll have the alias permanently.
Aliases in Windows are also possible, but are a bit trickier; see Aliases in Windows command prompt.
You don't have to use npx gulp for gulp because it is installed globally
So, there's gulp.cmd, gulp.ps1 and gulp starting npx gulp somewhere in PATH, so you can run them from there
this answer is low effort, feel free to edit it
if you install gulp globally:
npm i -g gulp
you will be able to just run gulp
I would avoid answers suggesting global installs (npm install -g). Global installs guarantee that everyone working on a project has their own unique set of tools, and the reason companies end up with huge wiki pages on "how to get the project working locally".
You mention the "bin config", but perhaps you're misunderstanding that one. That's not for specifying commands that your app will use. If you were making a cli application, the bin section in package.json is where you would specify the commands exported by your project. For example, gulp exports the gulp command like:
"bin": {
"gulp": "./bin/gulp.js"
},
Instead, you would add dependencies needed by your application to devDependencies. This ensures that everyone using the project will get the same version of all of the tools, such as gulp, tsc
Using npx is a far better solution because you can add everything the project needs in devDependencies, and npx will use that version. For the common command line tools, an alias such as #machineghost suggests is a better way to go, but to expand on it a bit:
Sometimes, the name of the command is different from the name of the package. In those cases, the alias can use:
alias tsc='npx --package=typescript tsc'
Normally, when running npx, it will prompt to install if there is not a version found in the current project. This is often a good safeguard, because it reminds you to add it to the devDependencies of the project. However, if you really want it to "just work" like a global install, you can add the "yes" flag:
alias command=`npx -y gulp`
This will use the version specified in the current project if present, but install it and run it directly if not.

`npm install` is not installing local package's sub-dependencies

I have a package (package-a) that depends on another package (package-b) which is not published to npm but is on my file system. When I run npm install from package-a, package-b's dependencies are not installed. I have to navigate to package-b's directory and run npm install manually. Is there a way to install both packages' dependencies with a single npm command?
Here's my directory structure:
/
...
shared/
...
javascript/
...
package-b/
package.json
package-a/
package.json
Per the docs, I placed the following in package-a/package.json. (I'm using npm 5+)
dependencies: {
package-b: "file:../shared/javascript/package-b",
}
When I navigate to /package-a and run npm install, it installs all of package-a's dependencies like normal and also copies the package-b directory to package-a/node_modules. This is presumably what lets me type require('package-b') instead of require('../shared/javascript/package-b') .
However, as I stated before, package-bs dependencies are not installed, so if I try to use package-a, I get an error when package-b is required because it is trying to use dependencies that do not exist locally.
Once again, to solve this, I can navigate to package-b and run npm-install, but I'm hoping there's a better solution as I may have many such sub packages and I'd like to avoid having to write a shell script to go install all my dependencies if I can do this with an npm command. (perhaps I just did something wrong and npm install should be working?)
Follow up question: when I run npm install from package-b's directory, the packages are installed there, but not in the version of package-b that got copied to /package-a/node_modules during the first npm install, yet everything still works. So now it seems like when I require('package-b') it is actually resolving to /shared/javascript/package-b and NOT /package-a/node_modules/package-b. So what's the point of copying the file in the first place?
Update
It turns out this is a bug in npm 5. It only occurrs when installing from a package-lock.json file. (Github Issue)
The files are (probably) not being copied, they're being symbolically linked (symlink). This essentially creates an alias/shortcut that looks like a real directory, but points to another path.
This is how the older npm link feature worked. The reason is the code stays "live"; Changes in the linked module are reflected whenever you run the module that's referencing them, meaning you don't have to npm update all the time.

creating an npm console application thats "installable" (like yeoman or gulp or grunt etc..)

I'm quite new to the whole NPM-stuff, however, I would like to create a new package that should be able to run as a console-app (like gulp and grunt).
So basically what I would like to do is making it possible to run
npm install -g mypackage
and then
mypackage
and that would then kick off the console application.
I have been using npm init to init my new package, I have also created the entry point (in my case app.js), and node app.js runs fine.
I have also used npm pack to create a package and npm install {path to my .tgz}.
This is my app.js:
console.log('Hi from NodeJS');
Nothing fancy so far.
The package is called "mypackage"
The problem is that when I type:
mypackage in my console the console application doesn't run.
Any ideas?
Br,
Inx
You're looking for bin.
To install one or more executable files to PATH, you shoul supply a
bin field in your package.json which is a map of command name to
local file name. On install, npm will symlink that file into
prefix/bin for global installs, or ./node_modules/.bin/ for local
installs.
For example, grunt-cli has this:
"bin": {
"grunt": "bin/grunt"
},
Where bin/grunt is a js file (yet without an extension defined).
P.S. If you're planning to ship this as a global package, don't forget to set preferGlobal.

Install node extensions without commands

I am doing an internship in a company.
I need to create a node server.
I installed node on the computer (Windows) and I should install some plugins like:
- nodejs-webpack
- colors
- uglify
Normally I need to enter a command like : npm install "theModule"
But the software can not access the internet (due to company restrictions) and support service can not authorize the software (or do not want).
Can I install modules in any other way ? (download from Google and slide archives in the correct folder for example).
If the answer is no, do you know how can i get around this security?
You need a private npm repository.
Check out this answer:
can you host a private repository for your organization to use with npm?
I found it !
Just for exemple, we will install 'nodejs-websocket' :
1) You just have to download it here.
2) Put files into your Node's directory (for me it's "C:\Program Files\nodejs\node_modules\npm\node_modules")
3) in your .js file just add this line : var ws = require("C:/Program Files/nodejs/node_modules/npm/node_modules/nodejs-websocket/")
Done ! Thanks for all :D
I added this as a comment on your own answer, but I figured I should add a real answer with a better explanation.
Normally when you run npm install package-name npm installs the package to a node_modules directory in the directory you are in at that moment. So if your app was located at C:\code\my-app then you would cd into that directory and run npm install package-name. This would create a node_modules directory at C:\code\my-app\node_modules if it didn't already exist. Then it would install package-name into that directory at C:\code\my-app\node_modules\package-name.
As long as the module is in the node_modules directory for your app, you can require the module in your code without entering a big long file path.
var ws = require('nodejs-websocket');
The place you manually installed your module is the global node_modules directory. It's where npm would install a module if you did npm install -g package-name. The global node_modules directory is added to your system path when you install npm. In other words, any modules you install in there would be accessible from the command line like any other command. For example:
npm install -g bower
That would install the "bower" package to the global npm module directory. Bower would then be accessible as a command line tool for you to use. For example:
bower install angularjs
The global directory is more for tools like that and not really for modules that you intend to use in your code. Technically you can require a module from anywhere by including the full path in the require call like you did, but the standard practice would be to place it in the node_modules directory in the root of your application, and then require it with just its name and not a full path.
Edit: Here's another tip that you might like to take advantage of as well.
When you normally install a module with npm install package-name, your application usually has a package.json file at the root of it. If it does, you can do npm install package-name --save and npm will add the package-name module to a list in your app's package.json file. Once a module is listed in your app's package.json file it's called a "dependency" of your app because it basically says your app depends on package-name.
Normally, when you have dependencies listed in package.json, you can completely delete your app's node_modules directory and then simply run npm install from within your app's root directory and npm will automatically install all dependencies it finds listed in your app's package.json file. Since your corporate firewall won't allow this automatic downloading of modules, you won't get that benefit. However it is still good practice to follow the same conventions.
A trick you can do to create your package.json file is to manually install your dependencies into your app's node_modules directory. Once you have the modules your app needs, you can instruct npm to create a package.json file for your app by simply running npm init. It will walk you through a few little prompts to fill out your package.json file with details about your app. It will then peek inside your node_modules directory to see if you've already installed any modules before having a package.json file. If it finds any, it will automatically add them to the dependencies field in the package.json file it creates :D
With a proper package.json in place you'll always have a nice tidy list of what dependencies your application needs, even if your node_modules directory gets deleted. Normally people add their app's node_modules directory to their .gitignore file, only checking in the package.json file. This way they don't store their dependencies in source control but they can still be easily installed on new machines that clone it by simply running npm install from inside the app's directory. In your case though you may want to just add node_modules to your source control since you can't let npm install dependencies automatically.

How to develop npm module locally

Lets say im working on an app, MyApp, and I want to build an NPM module for it, MyModule. Right now I can think of two ways to develop it:
Makes changes -> save -> npm install /path/to/module in MyApp
Same as 1, except run npm install /path/to/module then editing it directly in node_modules then copying the changes over.
What I'd like is an easier workflow. One where I can simply save the file, refresh the page, and my changes are there. Is that possible? For example, I know in Gemfiles I can just link to another directory as the path. Pretty sure I can't do that with npm tho.
You're looking for the npm link command, which is a two steps process:
Run npm link from your MyModule directory: this will create a global package symlinked to the MyModule directory
Run npm link MyModule from your MyApp directory: this will create a MyModule folder in node_modules, symlinked to the global symlink (and thus to the real location of MyModule).
To add on to Paul's answer, you can also do a shortcut for the above by doing the following from within your MyApp directory:
npm link ../MyModule

Categories