Elastic Beanstalk dependencies not available in npm install? - node.js

I have read EB Documentation to understand how i can set external dependencies for my app. My app is to be installed in a nodejs container which automatically executes npm install and npm start. So to build the static dependencies I use
"scripts": {
"postinstall": "bower install -F && gulp build",
"start": "node server.js",
"test": "NODE_ENV=test mocha server/test --recursive"
}
Which isnt working fine due to error in gulp build, which is as follows
[12:03:22] Starting 'styles'...
{ [Error: spawn ENOENT: Missing the Sass executable. Please install and make available on your PATH.]
message: 'spawn ENOENT: Missing the Sass executable. Please install and make available on your PATH.',
showStack: false,
showProperties: true,
plugin: 'gulp-ruby-sass',
__safety: { toString: [Function] } }
[12:03:22] 'css' all files 0 B
So I did this
packages:
rubygems:
sass: ''
and placed the file in .ebextensions/01config.config but no change in error. Have tried doing numerous other things but ended up doing the following as my last idea
"postinstall": "bower install -F && gulp build && sh postgulp.sh",
and creating a postgulp.sh file in the project root
#!/bin/bash
pwd
ls
if hash sass 2>/dev/null; then
sass --update ./client/css:./public-debug/css --sourcemap=auto;
else
echo >&2 "I require sass but it's not installed. Continuing without sass.";
fi
Still no luck. Even though I have sass in rubygems dependency but its not in the PATH. Why? When are ebextensions scripts executed as opposed to npm install and postinstall? Why is some thing that is installed in ebextensions only available to those scripts and not to npm? Why dosent gulp-ruby-sass pick up sass?

There can be two versions of ruby on the instance - one in /usr/bin and another one in /opt/elasticbeanstalk/lib/ruby.
Since you said SAAS is installed in the latter you need to make sure that the version of ruby on path when running your app is the same.
Most likely node is trying to use system ruby in /usr/bin and hence cannot find the gem.

Related

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.

How to run Procfile with multiple commands on Heroku?

I'm trying to deploy the static website to Heroku and I struggle how to correctly setup the Procfile.
I have next command to run on the server:
npm install
gulp build (will make a build with /public folder)
http-server (will serve /public by default)
What I've tried:
web: npm install; gulp build; http-server
web: npm install & gulp build & http-server
Okay, so I've spent a bit of time on that and came up with the answer. By default, heroku is installing all packages from the package.json file, so npm install is no longer required. Then what was left - gulp build and http-server.
For that case, I've added "postinstall" : "gulp build" to my package.json and it left me with web: http-server.
Simplifying things have actually solved the problem. Not sure how useful that information might be to you, but it's worth to share.
You may also have been looking for && or a library like concurrently.
Regardless, and per the docs, use Procfile as nothing more than an entry point to your npm start script.
Use the npm scripts lifecycle as stated (npm-scripts).
Directly From The Documentation (heroku-build-process).
"scripts": {
"start": "node index.js",
"test": "mocha",
"postinstall": "bower install && grunt build"
}
Heroku has adopted the 'there's an app for everything' mantra, but for buildpacks. Whatever you're building, there's a buildpack for it.
You can run multiple command inside Procfile using sh -c command :
worker: sh -c 'firstCommand && secondCommand && etc...'
Notes : Procfile should be at the project root level.
For example :
worker: sh -c 'cd backend && yarn install && yarn build && yarn start-worker'
Or in your case (if u have Procfile at the same level as package.json) :
web: sh -c 'npm install && gulp build && npm run http-server'

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/

How does "npm" run "npm test"?

I always thought that npm test command just launches what I would write in package.json inside scripts: { test: ...} section. But I have this weird bug when it doesn't work.
So, I have this piece of config in package.json
"scripts": {
"start": "node index.js",
"test": "mocha tests/spec.js"
}
When I try to run tests I type npm test in terminal and had this error:
module.js:340
throw err;
^
Error: Cannot find module 'commander'
But everything is OK when I type just mocha tests/spec.js. Any ideas why is that?
UPDATE:
I've tried to install commander and I had an error Cannot find module 'glob'. After installing glob I have
Error: Cannot find module '../'**
But actually question is why do I have these errors and why is everything OK when running mocha tests/spec.js?
You may have two versions of mocha installed: one globally (npm install -g mocha) and one locally, which appears to be broken.
When you run a script through npm, either as npm run-script <name> or with a defined shortcut like npm test or npm start, your current package directory's bin directory is placed at the front of your path. For your package that's probably ./node_modules/.bin/, which contains a link to your package's mocha executable script.
You can probably fix this by removing the local mocha and reinstalling it with --save-dev:
rm -rf node_modules/mocha
npm install --save-dev mocha
That should get you a working local copy of mocha with all its dependencies (commander etc.) installed.

How can I invoke npm on heroku command line (to install bower components)?

Bower is for client side Javascript what npm is for the server side and reads a component.json file to recognize dependencies that should be fetched at deploy time so I'd be happy it heroku would run it at slug compilation time.
Unfortunately I can not invoke npm or bower from a heroku console or one-off command (heroku run "npm help") (heroku run bash -> npm help) as it's possible with ruby's rake. I've put npm and node (latest/x versions) in my package.json but in the engines section, not the dependencies.
I think this could be solved by customizing the node buildpack but I consider this a little too heavy task just for activating something so obvious.
You can also setup a postintall command, something like this in your package.json
"dependencies": {
"bower": "0.6.x"
},
"scripts": {
"postinstall": "./node_modules/bower/bin/bower install"
}
Then npm install will also install bower dependencies.
Pros : one command to rule them all.
Cons : you unnecessarily embed bower as a dependency.
You can use run like this:
heroku run npm install git://github.com/webjay/kaiseki
You should declare NPM dependencies in the package.json file
All you install from shell will be deleted on exit shell. You are in a cloned instance.
You can use bower directly like this
"dependencies": {
"bower": "^1.7.9"
},
"scripts": {
"postinstall": "sudo bower install --allow-root "
}

Resources