Splitting npm scripts into multiple files - node.js

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"
},

Related

Npm install from repo not running `prepare`

I have an npm package for common components hosted on an internal git server. For some reason when I call npm install in another project I want to consume this in it will not run the prepare hook. Obviously, this does not work since the npm package needs a /dist folder in node_modules to be able to consume the package.
I have already tried things such as using the deprecated prepublish hook and even that does not get called. I also tried to do postinstall to see if I could build after install, while that hook did get called it failed because the devDependencies were not installed
package.json
{
"name": "common-components",
"version": "0.1.0",
"scripts": {
"prepare": "npm run build",
"build": "ng build",
...
},
"private": true,
"dependencies": {
...
},
"devDependencies": {
...
},
}
command being used for install
npm install --save git+ssh://{URL-to-common-components-repo}}
I have read through the npm-scripts documentation https://docs.npmjs.com/misc/scripts thoroughly and it seems like they insist that prepare hook should always be called for this exact use-case
Updated 5/6/2019
Just as a note I found this bug on NPM community https://npm.community/t/using-npm-ci-does-not-run-prepare-script-for-git-modules/632/4.
I am using npm 6.4.1 which should work according to the bug
One thing to check that hit me on a package recently - if there is a .gitignore and not .npmignore npm may be ignoring your /dist folder. Adding an empty .npmignore worked in this case.
"If there’s no .npmignore file, but there is a .gitignore file, then
npm will ignore the stuff matched by the .gitignore file. If you want
to include something that is excluded by your .gitignore file, you can
create an empty .npmignore file to override it."
from https://docs.npmjs.com/misc/developers
For those that are wondering the status of this. I was unable to ever get it to work. What I ended up doing was hosting the components on a private npm registry and that works fine since the npm publish command will do the build and only publish the dist folder
If adding an empty .npmignore does not help, you can try specifying all files in dist explicitly in package.json#files. If this works you might want to consider using a wildcard pattern that matches the files in dist to simplify the package.json.
package.json
...
"files": [
"source",
"dist/cjs/main.js",
"dist/es/main.js"
]
}
see this comment to a similar issue in the npm/cli repository https://github.com/npm/cli/issues/1287#issuecomment-635021757
It's very likely that your dist/ folder is in your .gitignore file. According to this response from an npm-cli maintainer:
In order to be able to properly prepare a git repo npm will run the
extracted files through npm-packlist in order to get the expected
files that are going to be placed in your node_modules folder.
Further checking the documentation of npm-packlist, we find that npm-packlist will respect the .gitignore file if it has nothing else to go off of:
If there's no package.json with a files list, and there's no
.npmignore file, but there is a .gitignore file, then ignore all the
files in the .gitignore file.
This article further expands on the idea.
It seems to me that the best fix is to explicitly declare the files that your package needs (including dist/) in the files section of your package.json file. Then you have complete control over what's included and the package size is minimized.
If you are using root user to npm install the package then the prepare script might not be triggered. The reason was the prepare child process has no permission to run (user account was set to default of 'nobody' when using npm with root). You can read more here: https://github.com/npm/npm/issues/17346
To fix this, in the lib package, create an .npmrc file and add:
unsafe-perm: true
Adding main in the package.json fixed this issue for me.
"main": "./dist/index.js",
"scripts": {
"build": "babel src --out-dir dist",
"prepare": "npm run build",
"lint": "eslint ."
},
node v14.15.4 npm 6.14.11

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.

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

Run npm scripts using local deps

Currently I run npm scripts using local deps this way:
package.json:
"scripts": {
"test": "node ./node_modules/karma/bin/karma start",
"node-test": "node ./node_modules/jasmine/bin/jasmine",
"build": "node ./node_modules/gulp/bin/gulp build"
},
I don't want to use global deps, since I can forgot to add deps to the package.json. This way when a local dep is missing, then I got an error message and I don't have problems because some deps are not installed globally, e.g. karma plugins.
Is there a better (shorter) way to define npm scripts using the local libs? Is this travis compatible?
edit:
If it wasn't obvious I have the same libs installed globally, but I want to use the local installs by these projects. That means when I start karma with karma start then the globally installed version will start the karma server, which means that if I don't have all of the karma plugins globally installed, then I got error.
Another problem that I have windows, so the solutions described here: How to use package installed locally in node_modules? do not work. Windows does not recognize the #!/bin/sh and the #!/usr/bin/env node head sections and there is no sh command as far as I can tell. At least not in webstorm terminal. Git bash has the sh command, but I want to run these npm scripts from webstorm terminal.
One possible solution could be to fix somehow webstorm so it could use sh from terminal. After that I could use $(npm bin) I assume. But that's just a guess. I am not sure whether this can be done.
npm automatically puts prepends the path ./node_modules/.bin to your PATH env before it executes commands run by using npm run (including the two "magic" shortcuts npm start and npm test)
npm scripts docs
You can just set this up with:
"scripts": {
"test": "karma start",
"node-test": "jasmine",
"build": "gulp build"
}
Assuming that you have karma, jasmine and gulp-cli listed in either your devDependencies or dependencies (so that they're install when doing npm install)
And yes, it is travis-compatible. Here is an example of a package that is tested on travis using tap which is installed locally as a module:
https://github.com/scriptoLLC/couchdown/

Run npm from subdirectories on Heroku

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"
}

Resources