How to disable local package dependency for `npm install --prefix`? - node.js

I have a project with at its root the following simplified package.json file:
package.json
{
"name": "parent-project",
"dependencies": {
...
}
}
In a subfolder that we'll call child-project, another package.json resides:
child-project / package.json
{
"name": "child-project",
"dependencies": {
...
}
}
Some code that I depend on uses the command npm --prefix ./child-project install to install dependencies in child-project. However, this always has the undesirable side-effect of altering child-project/package.json like so:
{
"name": "child-project",
"dependencies": {
...
"parent-project": "file:.." // <- I don't want this!
}
}
When I execute cd ./child-project && npm install all is fine and child-project/package.json remains untouched, so my hunch is that it has to do with --prefix but documentation on --prefix is very obscure.
Is there a way to disable this behaviour and prevent NPM from altering the child-project/package.json?

Seems like there are some issues with the --prefix.
However, I couldn't find any issue while I was testing with different modules which have sub-packages.
Hence, according to one of the npm contributors, it is going to be refactored or removed in a future release, which means it is not the best choice to use it at least for now. So I recommend you go through the traditional way and avoid using --prefix.
I think we're gonna close this as a wontfix as --prefix is not the best flag to be promoting. We do eventually want to refactor or remove it but for now we should at least not be promoting it.

Related

Using subdependencies in npm script

Say I have a private npm package, #myprivate/repo which has the following contents in its package.json:
"scripts": {
"example": "db-migrate"
},
"bin": {
"foo": "bin/foo"
}
Where bin/foo is:
#!/bin/bash
npm run example
I now pull this into a parent repo with npm install:
package.json:
{
"dependencies": {
"#myprivate/repo": "*"
},
"scripts": {
"example": "unrelated command",
"useful": "foo"
}
}
Then running npm run useful results in the foo bin script getting called, which then attemps to call unrelated command. How do I scope the invocation to the dependency? How can I force a bin script to package its own npm dependency and rely on that? Is nested scripts in nested dependency package.json the best way, or is there a better more canonical solution?
I ended up being able to get the behaviour I want by changing the last line of bin/foo to:
npm explore #myprivate/repo npm run example
This does feel a little bit happy (I'm referencing the repo using npm explore from within itself), but it does get the job done. Would love to hear of a better solution

Visual Studio Code global typings definitions

I was wondering if there is any way to save global typings definitions for VS Code. I know you can add them to your project but I think it would be much cleaner if I could install these globally, so it wouldn't show up under my project. Also, it would make it much faster to start a new project if VS Code already knew all these definition without me having to add them every time I start.
I'm not looking for much, having definitions for Node, JQuery and Express would suffice for now.
Thanks
I do not really think that local definitions are the problem. Sometimes you might get to the point when you do need to have different versions of the same definition files in different projects or do not want to have some of them due to the conflicts with systems ones in lib.d.ts. Therefore I believe local storage is a better choice.
I use it all the time and to overcome your issues I can recommend to do the following.
Add "files.exclude" to the .vscode/settings.json:
{
"files.exclude":
{
"typings": true
}
}
This will hide all typings so you do not see them in project.
To start project from scratch fast you can have a tsd.json with commonly used definitions. For example:
{
"version": "v4",
"repo": "borisyankov/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"es6-promise/es6-promise.d.ts": {
"commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff"
},
"jasmine/jasmine.d.ts": {
"commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff"
}
}
}
And correspondingly in your package.json add postinstall action like this:
{
"scripts": {
"postinstall": "tsd update --save --overwrite"
}
}
After that all you have to do to initialize definitions for the new project is to run
npm install
This will fetch all definitions and you will not see them in the IDE.
Hope this will help.

Is it possible to consume environment variables inside of npm / package.json?

I'm attempting to build a package.json so that when running a NodeJS app on Heroku it will run the scripts.postinstall step using an environment variable. For example:
...
"scripts": {
"postinstall": "command $ENV_VAR"}
},
...
I've looked at the docs and wasn't able to find something saying I can.
Is this even possible? Is this even desirable and "I'm Doing It Wrong"™?
Ignore the nay-sayers. You can do this in a cross-platform manner using cross-var:
"scripts": {
"postinstall": "cross-var command $ENV_VAR"
}
Updated answer due to new packages having been written
You can use the cross-var package to do this in a clean way:
...
"scripts": {
...
"postinstall": "cross-var command $ENV_VAR",
...
},
"dependencies": {
...
"cross-var": "^1.1.0",
...
}
...
Original answer
To answer the last questions, because they're the most important one: yes, no, and absolutely, because you've just broken cross-platform compatibility. There is no guarantee your environment syntax works for all shells on all operating systems, so don't do this.
We have a guaranteed cross-platform technology available to us already: Node. So, create a file called something like bootstrap.js, and then make npm run node bootstrap as your postinstall script. Since the code inside bootstrap.js will run like any other node script, it'll have access to process.env in a fully cross-platform compatible way, and everyone will be happy.
And many, many, many things that use common utils have node equivalents, so you can npm install them, locally rather than globally, and then call them in an npm script. For instance mkdir -p is not cross-platform, but installing the mkdirp module is, and then an npm script like "ensuredirs": "mkdirp dist/assets" works fine everywhere when run as npm run ensuredirs
And for convenience, the most common unix utilities have their own runner package, shx, which is fully cross-platform and makes the lives of devs even easier, with the "if you're writing code" equivalent being fs-extra.

Install node_modules to vendor

How can I install npm modules locally for each project to vendor/node_modules and make package.json file see them.
I don't want to move package.json to vendor folder
I have bower and in .bowerrc I specify the bower_components path - that is super easy.
How can I do that with npm ?
I`ve read the docs, npmrc docs, some questions here, googled, wasted more than an hour - still no luck. This is ridiculously hard for such an easy task.
I don't care about minuses, just tell me how to do that finally.
Frustrated by the fact that there seems to be no built in way to install into a node_modules folder in an arbitrary subfolder, I came up with a sneaky solution using the two following scripts:
preinstall.js
var fs = require("fs");
try
{
fs.mkdirSync("./app/node_modules/");
}
catch(e)
{
}
try
{
if(process.platform.indexOf("win32") !== -1)
{
fs.symlinkSync("./app/node_modules/","./node_modules/","junction");
}
else
{
fs.symlinkSync("./app/node_modules/","./node_modules","dir");
}
}
catch(e){}
postinstall.js
var fs = require("fs");
try
{
if(process.platform.indexOf("win32") !== -1)
{
fs.unlinkSync("./node_modules/");
}
else
{
fs.unlinkSync("./node_modules");
}
}
catch(e){}
All you need to do is use them in your package.json file by adding them to the scripts option:
"scripts": {
"preinstall": "node preinstall.js",
"postinstall": "node postinstall.js"
},
So, the big question is: what does it do?
Well, when you call npm install the preinstall.js script fires which creates a node_modules in the subfolder you want. Then it creates a symlink or (shortcut in Windows) from the node_modules that npm expects to the real node_modules.
Then npm installs all the dependencies.
Finally, once all the dependencies are installed, the postinstall.js script fires which removes the symlink!
Here's a handy gist with all that you need.
You cannot, not using built-in npm functionality.
This discussion on the npm github repository covers the issue. It's also being addressed in this answer which is part of their FAQ.
You can still do the installs "manually" by copying modules into your /vendor directory and then calling them using the require("./vendor/whatever") syntax...but that means each require needs to use your new custom location. There are a few ways you could handle this but they all mean you are doing extra work in your source to accomodate the custom location.

What is the proper package.json manner to publish a npm package developed with Browserify?

I am publishing a npm package developed with Browserify, and wonder what is the proper manner to construct a package.json.
The package is a node server-client app (it is actually atom package), and the client side is based on Browseriy.
./www/js/index.js -> ./www/js/index.bundled.js
The required modules are marked and highlight.js.
The both modules are used only on the client side code/file which is bundled by blowserfiy.
A lazy and simple solution would be simply, just to have
package.json A
{
......,
"dependencies":
{
...,
...,
"highlight.js": "*",
"marked": "*"
}
}
and to include the www/js/index.bundled.js file in the npm package files as it is after the browserify in my local dev environment.
However, now I think the npm package.json can be one of the below:
package.json B
{
......,
"dependencies":
{
...,
...,
},
"devDependencies":
{
"highlight.js": "*",
"marked": "*",
"browserify": "*"
}
}
In this case, browserified ./www/js/index.bundled.js file is left in the npm package, and treat marked and highlight.js as a devDependencies, and also browserify.
Then
package.json C
{
......,
"dependencies":
{
...,
...,
"highlight.js": "*",
"marked": "*",
"browserify": "*"
},
"scripts": {
"run": "browserify ./www/js/index.js -o ./www/js/index.bundled.js"
}
}
Just let you know, I have never tried this, and don't know this scripts-run actually runs on npm install myPackage, perhaps not, and maybe you know the proper configuration, maybe there's no such a thing.
In this scenario, ./www/js/index.bundled.js is excluded from the npm package file, and built from the latest npm packaged marked and highlight.js.
The reason I think this manner is somewhat proper is especially in the scenario the npm modules are used and shared in both server and client side.
For instance, take a look at dnode. This RPC module is developed by the same author of browserify (#substack), and should share the same version of dnode module in both server and client side. If a pre browserified ./www/js/index.bundled.js is bundled in the published npm package, it will be outdated compared to server side dnode. Sure we may be able to specify the version to install by package.json, but it's better to use the latest on both server and client side.
Any suggestion? Thanks.
I suggest to use second choice and specify browserify as a devDependency.
You have to build it before you publish your package to npm registry, so users won't need to install browserify themselves.
It's also useful to add a Makefile and make as a prepublish script.

Resources