Run npm from subdirectories on Heroku - node.js

I have a project which contains 2 subprojects:
First is the API
Second is the client
And both of these projects have their own dependencies mapped in their own packages.json files, which is placed in each subdir.
So the question is how to run npm install from sub directories on heroku?
I tried putting something like this in the main npm file
"scripts": {
"postinstall": "cd my_subdir; npm install"
}
But it doesn't work, showing can't cd to my_subdir

Utilize npm's --prefix option:
"scripts": {
"postinstall": "npm install --prefix ./my_subdir"
}

Related

running windows Comman_Prompt command through package.json scripts

I need to run in command line (cmd)
npm run build
and after that, I need to run
xcopy C:\fileOne C:\fileTwo
BUT, I would like to run only one command and to execute both of those above.
So I thought maybe my package.json should look like this:
"scripts": {
"build": "react-scripts build",
"copy": "xcopy C:\path\firstFile C:\path\secondFile",
"zack": "npm run build && npm run copy",
},
based on this idea:
"scripts": {
"a1": "command1",
"a2": "command2",
"zack": "npm run a1 && npm run a2",
},
and then I could run in command line:
npm run zack
but I'm not managing to make it happen
(the reason why I'm doing this, is: I want to change source code in SubliteText 3 (HTML JS CSS) and automatically to send (copy-paste) in Eclipse (in some other project) )
I want to do this:
My main problem is how to put local directory path inside the string in package.json file.
Instead of writing commands directly inside the package.json you should write a script file that handles it for you.
Something like
var fs = require('fs');
fs.createReadStream('PATH_TO_FILE_ONE').pipe(fs.createWriteStream('PATH_TO_NEW_FILE'));
save the above script as something like afterBuild.js
and in your package.json just do zack as npm run build && node afterBuild.js
I installed npc module:
npm install ncp -g
npm install ncp --save
then I created a file: afterBuild.js and I inserted this code inside:
var ncp = require("ncp");
ncp("C:/directory/file.txt", "C:/destination/directory/file.txt", callback);
function callback(){} //empty function, I don't need it for the start
and in package.json i wrote:
"scripts": {
"build": "react-scripts build",
"zack": "npm run build && node afterBuild.js"
},
and I run it form command line like:
npm run zack

cross platform "rm" command

I currently have the following script in my package.json for deleting all ".js" files in my bundles folder for when I run "npm run build". It works fine when running it in dev servers but breaks when it is run in a Windows machine.
{
"scripts": {
"build": "rm bundles/*.js && webpack",
},
}
Since I am hashing all my build files, I am required to delete them all before adding new ones, such that I don't end up with a bunch of old builds.
Is there a "rm bundles/*.js" that would work in both Mac and Windows?
The npm package rimraf is available for command-line usage in scripts.
First install locally into your project:
$ npm install --save-dev rimraf
Then update the build script in your package.json file:
"scripts": {
"prebuild": "rimraf bundles/*.js",
"build": "webpack"
}
The rimraf command (named after rm -rf) deletes the files.
Documentation:
https://www.npmjs.com/package/rimraf#cli
rimraf is a well established project with over 3,000 4,000 5,000 ⭐s on GitHub.
Take a look at shelljs:
ShellJS is a portable (Windows/Linux/OS X) implementation of Unix
shell commands on top of the Node.js API. You can use it to eliminate
your shell script's dependency on Unix while still keeping its
familiar and powerful commands. You can also install it globally so
you can run it from outside Node projects - say goodbye to those
gnarly Bash scripts!
And further to shelljs/shx, which provides the following example:
{
"scripts": {
"clean": "shx rm -rf build dist && shx echo Done"
}
}
An alternative:
You may also want to take a look at Gulp or Grunt, both so called Task Runners. Gulp has gulp-clean and Grunt has grunt-contrib-clean. Both aim to delete folders and/or files.
Let's take Grunt for example:
Add the Grunt CLI with npm i -g grunt-cli to your system
Add the needed packages to your project with npm i --save-dev grunt grunt-contrib-clean
Create a file named gruntfile.js
Add the following lines:
module.exports = (grunt) => {
'use strict';
grunt.initConfig({
clean: ['bundles'],
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.registerTask('default', ['clean']);
};
Update your script "build": "grunt && webpack"
Cross-platform, no dependencies
If you're like me and don't want to add 11 dependencies just to delete a directory, you can use node exit codes to conditionally run scripts:
e.g. Remove the ./dist folder
{
"scripts": {
"clean": "npm run clean:win && npm run clean:lin",
"clean:win": "node -e \"if (process.platform === 'win32') process.exit(1)\" || , if exist dist rmdir /Q /S dist",
"clean:lin": "node -e \"if (process.platform !== 'win32') process.exit(1)\" || rm -rf dist",
}
}
npm run clean
If you do not concern about 'rm/del not found' console.log, here is the short and simple solution, no additional dependencies are required, rm works on Mac and Linux, del works on Windows:
{
"scripts": {
"build": "(rm bundles/*.js || del bundles/*.js) && webpack",
},
}
Update: recursive-fs added a CLI for deleting a folder so you can now do:
"scripts": {
"clean": "recursive-delete \"./bundles\""
}
Original:
If you decide you don't need 11 additional packages just to delete a single folder, you can use recursive-fs and a short script:
node -e \"require('recursive-fs').rmdirr(require('path').resolve('bundles'), ()=>{})\"
Alternatively, someone could write an NPM package that does this and has only a single dependency on recursive-fs, which would still put it at 9 packages fewer than rimraf. Another option would be to fork recursive-fs and publish an NPM package that includes a CLI in it that makes using it for recursive deletions easier.

why package.json script works fine on local project but doesn't work on a dependency project

I have created a npm module(let call it ModuleA) and defined clean script in its package.json file like below:
"scripts": {
"test": "nyc mocha tests/ --opts mocha.opts",
"build": "babel -d dist/ src/",
"prepublish": "yarn run clean && yarn run build",
"postinstall": "yarn run clean && yarn run build",
"clean": "rimraf ./dist"
},
I use rimraf to remove the dist directory. This dependency is defined in devDependencies as "rimraf": "^2.6.1". It works fine on this project. But in one of my other project (let call it ModuleB) which has a dependency on this module, the yarn install doesn't work and I get below error:
$ rimraf ./dist
sh: 1: rimraf: not found
this error happens when npm/yarn is building the ModuleB. I have checked that rimraf exist in node_modules/.bin directory in ModuleB. It works fine if I install rimraf globally. I wonder how I can make the npm/yarn to use rimraf from node_modules/.bin/rimraf?
BTW, I also put the rimraf in devDependencies in ModuleB.
I tried to update the script in ModuleA to use rimraf from node_modules/.bin/rimraf as below:
"clean": "node_modules/.bin/rimraf ./dist"
it works fine on ModuleA. But I got below error when run yarn install on ModuleB:
$ node_modules/.bin/rimraf ./dist
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
sh: node_modules/.bin/rimraf: No such file or directory
error Command failed with exit code 127.
See those issues:
https://github.com/yarnpkg/yarn/issues/721 (postinstall hook doesn't appear to be run #721)
https://github.com/yarnpkg/yarn/issues/853 (preinstall and postinstall are not run #853)
https://github.com/yarnpkg/yarn/issues/614 (Bug: issue with postinstall scripts in git-hooks package)
Now make sure that yarn clean and npm clean works as expected.
For example this will not work if you didn't install rimraf globally:
$ rimraf ./dist
But this should work:
$ ./node_modules/.bin/rimraf ./dist
Test those commands first:
npm run clean
and:
yarn run clean
to use the "clean": "rimraf ./dist" script defined in package.json.
Note that ./node_modules/.bin is added to your PATH when you run package.json scripts.
Try running the commands from the simple ones where you run the script directly without npm or yarn, then test with both npmand yarn, and then finally try to narrow down the problem with postinstall hooks.

Package.json for server and client

I want to install package.json for client side from my server side package.json as the server side is using node and client side is using angular 2
directory structure
server-app
--bin
--node_modules
--package.json
--client-app
--app
--node_modules
--package.json
now the problem is:
I have to run this command npm install from server app folder and also from server-app/client-app folder separately this will create deployment issues
what I want is to run only one time npm install from i.e server-app and it will automatically install the server-app package.json and client-side-app
package.json too.
Any help will be highly appreciated
I think what you need is a npm module called concurrently.
With concurrently installed in your root folder you can run multiple custom npm scripts.
For example: you can create 2 separate scripts that are installing the dependencies (client-install and server-install) and then create install-all-deps script that will run both scripts one after another and install all deps in both directories.
{
"scripts": {
"client-install" : "cd client && npm install",
"server-install" : "cd server && npm install",
"install-all-deps": "concurrently \"npm run server-install\" \"npm run client-install\""
}
}
Here is the npm module https://www.npmjs.com/package/concurrently. Quoting doc:
Run multiple commands concurrently. Like npm run watch-js & npm run
watch-less but better.
Hope this helps.
Structure your application in the following way,
app
--server-app
--client-app
--node_modules
--package.json
This way you can have single package.json file

Splitting npm scripts into multiple files

is there a way to split npm scripts into multiple files?
Currently I have next structure:
"pages-build-js": "browserify pages/dev/js/init.js -o pages/static/js/bundle.js",
"pages-build-scss": "node-sass pages/dev/scss/init.scss > pages/static/css/main.css",
However, is there a way, I can move these scripts in separate package.json in pages directory and then to run it from parent directory?
The problem is that when I make it, looks like it doesn’t see any local packages from parent directory. How can I solve it?
Thanks
I'm not sure if this is what you want but I had a project where we had a separate package.json for our backend.
To set everything up we hat this in our main package.json
"scripts": {
"setup": "npm install && cd ./src/backend && npm install"
},
Which install all packages from the two files.
You should also be able to run other npm scripts that way
So something like this
"scripts": {
"build-js": "cd ./pages && npm run pages-build-js"
},

Resources