babel watch on docker - node.js

i set docker instance with node.
i want to develop on this instance and use babel to "compile" my node code.
i use #docker/cli to compile with watch flag and i use nodemon with -L flag.
for some reason, nodemon is watching file changes great but not babel.
any idea?
this is my docker-compose.yml
main-app:
build: ./mainApp
user: "root"
command: yarn run start:watch
environment:
NODE_ENV: production
PORT: 8080
volumes:
- ./mainApp:/app
- /app/node_modules
ports:
- '8080:8080'
this is package.json:
"scripts": {
"build": "babel src --out-dir public",
"serve": "node public/server.js",
"build:watch": "babel --watch src -d public -s",
"serve:watch": "nodemon -L public/server.js",
"start:watch": "concurrently -k \"npm run build:watch\" \"npm run serve:watch\""
},
"dependencies": {
"express": "^4.16.1"
},
"devDependencies": {
"#babel/cli": "^7.0.0-beta.35",
"#babel/core": "^7.0.0-beta.35",
"#babel/preset-env": "^7.0.0-beta.35"
},
as you can see i use concurrently to run them both.
what can be the problem babel is not watching my files?
PS: it works fine on my local machine

babel-watch didn't worked out for me.
As I was compiling code through babel cli and outputting in some another directory (to be used by second docker container)
I ended up using nodemon exec option
In my package.json, created new script especially for docker:
"docker-build:watch": nodemon -L --watch src --exec 'npm run build:watch'
and then using npm run docker-build:watch instead of npm run build:watch

Babel CLI uses Chokidar to watch file changes, to make it work inside a linux image you need to:

CHOKIDAR_USEPOLLING=true babel --watch


You can read more about this here

I was having a similar issue and ended up using 'babel-watch'. IT still required me to use the -L flag to enable poling to get it to work in Docker. I have not tried it, but the same approach may work with babel itself.
Take a look at the babel-watc readme for more details. https://github.com/kmagiera/babel-watch#troubleshooting
You filesystem configuration doesn't trigger filewatch notification
(this could happen for example when you have babel-watch running
within docker container and have filesystem mirrored). In that case
try running babel-watch with -L option which will enable polling for
file changes.

Related

Cloud Run: The user-provided container failed to start and listen on the port defined provided by the PORT=8080

I am trying to deploy a containerized node-typescript-express app to cloud run but I am unable to do so, receiving the following error:
The user-provided container failed to start and listen on the port defined provided by the PORT=8080
Here is my Dockerfile config:
FROM node:18.13.0 as base
WORKDIR /home/node/app
COPY package*.json ./
RUN npm i
COPY . .
FROM base as production
ENV NODE_PATH=./dist
RUN npm run build
In my code, I'm declaring port as
const PORT = process.env.PORT || 8080;
I also have a .env file where I was setting port, but I deleted the port key - as far as I know, GCP cloud run injects the port variable anyway.
Here is a screenshot from my project settings on GCP. I uploaded my image by building it locally with docker-compose build, tagging it, and uploading it to the GCP container repository.
I've tried manually setting the port in the code, removing the env file completely, specifying a different port, etc. I'm not even sure if the port is specifically the error and it's just some kind of catch-all.
Here's my package.json:
{
"name": "weather-service",
"version": "0.0.0",
"description": "small node server that fetches openweather api data",
"engines": {
"node": ">= 18.12 <19"
},
"scripts": {
"start": "NODE_PATH=./dist node dist/src/index.js",
"clean": "rimraf coverage dist tmp",
"dev": "ts-node-dev -r tsconfig-paths/register src/index.ts",
"prebuild": "npm run lint",
"build": "ttsc -p tsconfig.release.json",
"build:watch": "ttsc -w -p tsconfig.release.json",
"build:release": "npm run clean && ttsc -p tsconfig.release.json",
"test": "jest --coverage --detectOpenHandles --forceExit",
"test:watch": "jest --watch --detectOpenHandles --forceExit",
"lint": "eslint . --ext .ts --ext .mts && tsc",
"lint:fix": "eslint . --ext .ts --ext .mts",
"prettier": "prettier --config .prettierrc --write .",
"prepare": "husky install",
"pre-commit": "lint-staged"
And lastly, here's my docker-compose file and how I'm executing the commands
docker-compose.yml
version: '3.7'
services:
weather-service:
build:
context: .
dockerfile: Dockerfile
target: base
volumes:
- ./src:/home/node/app/src
container_name: weather-service
expose:
- '8080'
ports:
- '8080:8080'
command: npm run dev
docker-compose.prod.yml
version: '3.7'
services:
weather-service:
build:
target: production
command: npm run start
docker.compose.dev.yml
version: '3.7'
services:
weather-service:
env_file:
- .env
environment:
- ${PORT}
- ${WEATHER_API_KEY}
Makefile
up:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
up-prod:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
down:
docker-compose down
build:
docker-compose build
If you are using Macbook, then below answer from Bk Lim in the below link might help you:
Cloud Run: "Failed to start and then listen on the port defined by the PORT environment variable." When I use 8080
Update: I managed to get it successfully deployed by changing my docker-compose files to a template I found on GitHub, here
My docker knowledge is minimal so if anyone has any idea why my old docker-compose wasn't working, I'd love to know.

Docker container is refusing connection

I am using Dockerfile for Nodejs project but its returning Connection refused error
When I run the app without Docker it works absolutely fine.
Command I use to build and run the docker container is as follows:
docker build -t myapp .
docker run -it -p 8080:8080 myapp
Running above command runs without any error but when I hit http://localhost:8080/test-url it fails
My dockerfile is as follows:
FROM node:16.16.0-alpine
ADD . /opt
COPY . .
RUN npm install
EXPOSE 8080
RUN chmod +x /opt/deploy.sh
RUN apk update && apk add bash
CMD ["/bin/bash", "/opt/deploy.sh"]
And my package.json is as follows (truncated to show only script):
"scripts": {
"start": "DEBUG=app* node index.js",
"build": "rimraf build && babel-node ./src --out-dir build/src && npm run docs",
"dev": "DEBUG=app* nodemon --exec babel-node index.js",
"lint": "eslint 'index.js' 'src/**/*.js' 'src/index.js'",
"docs": "apidoc -i src/ -o public/docs",
"prepare": "husky install",
"lint-staged": "lint-staged"
},
For development I use following command which works fine::
npm run dev
For deploymeent I run deploy.sh which has env variables and final command as ::
npm run build
npm run start
Even when I am trying http://localhost:8080/test-url by loging into docker interactive terminal it returns same error - Connection Refused
Your Port mapping looks right to me. Did you check your firewall? Maybe it is blocking the connection. It could also be helpful to test, if you can run an NGINX-Container on Port 8080. That way you can check if it is a general configuration-problem with Docker or a specific problem of your Image.
Also, did you try to set your node server to listen to 0.0.0.0 instead of localhost? I'm not sure how Docker handles IPs in the Containers, but I was thinking maybe it is called by it's internal ip. If that is the case and your server listens to localhost only, it shouldn't accept the connection.
I hope one of these things can point you in the right direction.

npm run points to different .env file

We are working on nodeJs/ExpressJs we have configured multiple .env files for development and production and pointing it to package.json for different execution process, we have naming conversation issues at scripts.
Whenever we run npm run prod it takes to preprod configuration. what could be the issues?
Update: we have figured that the suffix of the script key is the same in the next script, after update/rename preprod to preProd the both runs fine. but why?
Eg :
"scripts": {
"dev": "clear; env-cmd -f ./config/hostedDev.env nodemon --exec babel-node index.js",
"prod": "clear; env-cmd -f ./config/prod.env nodemon --exec babel-node index.js",
"preprod": "clear; env-cmd -f ./config/preprod.env nodemon --exec babel-node index.js"
},
Apparently the issue is with the word 'pre'.
If you would have noticed it runs both preprod and prod commands (pre running first).
If you change the script name to 'postprod' the postprod script will run later.
So, I guess npm uses 'pre' as to run before the 'prod' script and then running 'prod' script itself.

Passing environment variable to pm2 is not working

I have two API in node js using babel and I have a package.json commands to use to make the application working this is the commands:
"build": "del-cli dist/ && babel src -d dist --copy-files",
"serve": "cross-env NODE_ENV=production node dist/index.js",
"start:noupdate": "cross-env NODE_ENV=development babel-node src/index.js",
"start:serve": "cross-env NODE_ENV=production node dist/index.js",
I have two domains one is https://api.website1.com.br and another is https://website2.com.br/api.
They have the same env file name but with another data for each database, that is .env.production and .env.development
When I make this "yarn build", my Linux execute this command :
"build": "del-cli dist/ && babel src -d dist --copy-files",
And this is working fine when I try to put in production mode on my real webservers, i go to the folder from the project and run this command to make the app online with PM2:
pm2 start npm -- run-script start:serve NODE_ENV=production
That will make this command work:
"cross-env NODE_ENV=production node dist/index.js"
The app runs just fine, but I have a problem he only runs one and doesn't create a new PM2 APP he just restarts what I start.
Example if I go to the folder in my https://api.website1.com.br and run this command first in this he starts, but I go to the another he doesn't start that but reload my already early app don't create a new one, what I'm doing wrong?
I manage to work this using pm2 ecosystem, that I found in this documentation from http://pm2.keymetrics.io/docs/usage/application-declaration/
I configure the default file and put a name my APP:
module.exports = {
apps : [{
name: "app",
script: "./app.js",
env: {
NODE_ENV: "development",
},
env_production: {
NODE_ENV: "production",
}
}]
}
and use this command pm2 start ecosystem.config.js and now is working, I post here to know if someone has the same problem

Docker /bin/bash: nodemon: command not found

I am trying to mount my working node code from my host into a docker container and run it using nodemon using docker-compose.
But container doesn't seems to be able to find nodemon.
Note: My host machine does not has node or npm installed on it.
Here are the files in the root folder of my project (test). (This is only a rough draft)
Dockerfile
FROM surenderthakran/nodejs:v4
ADD . /test
WORKDIR /test
RUN make install
CMD make run
Makefile
SHELL:=/bin/bash
PWD:=$(shell pwd)
export PATH:= $(PWD)/node_modules/.bin:$(PWD)/bin:$(PATH)
DOCKER:=$(shell grep docker /proc/1/cgroup)
install:
#echo Running make install......
#npm config set unsafe-perm true
#npm install
run:
#echo Running make run......
# Check if we are inside docker container
ifdef DOCKER
#echo We are dockerized!! :D
#nodemon index.js
else
#nodemon index.js
endif
.PHONY: install run
docker-compose.yml
app:
build: .
command: make run
volumes:
- .:/test
environment:
NODE_ENV: dev
ports:
- "17883:17883"
- "17884:17884"
package.json
{
"name": "test",
"version": "1.0.0",
"description": "test",
"main": "index.js",
"dependencies": {
"express": "^4.13.3",
"nodemon": "^1.8.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"api",
"nodejs",
"express"
],
"author": "test",
"license": "ISC"
}
index.js
'use strict';
var express = require('express');
I build my image using docker-compose build. It finishes successfully.
But when I try to run it using docker-compose up, I get:
Creating test_app_1...
Attaching to test_app_1
app_1 | Running make run......
app_1 | We are dockerized!! :D
app_1 | /bin/bash: nodemon: command not found
app_1 | make: *** [run] Error 127
test_app_1 exited with code 2
Gracefully stopping... (press Ctrl+C again to force)
Can anyone please advice?
Note: The Dockerfile for my base image surenderthakran/nodejs:v4 can be found here: https://github.com/surenderthakran/dockerfile_nodejs/blob/master/Dockerfile
The issue has been resolved. The issue boiled down to me not having node_modules in the mounted volume.
Basically, while doing docker-compose build the image was build correctly with the actual code being added to the image and creating the node_modules folder by npm install in the project root. But with docker-compose up the code was being mounted in the project root and it was overriding the earlier added code including the newly created node_modules folder.
So as a solution I compromised to install nodejs on my host and do a npm install on my host. So when the code my being mounted I still got my node_modules folder in my project root because it was also getting mounted from my host.
Not a very elegant solution but since it is a development setup I am ready for the compromise. On production I would be setting up using docker build and docker run and won't be using nodemon anyways.
If anyone can suggest me a better solution I will be greatful.
Thanks!!
I believe you should use a preinstall script in your package.json.
So, in the script section, just add script:
"scritpts": {
"preinstall": "npm i nodemon -g",
"start": "nodemon app.js",
}
And you should good to go :)
Pretty late for an answer. But you could use something called as named volumes to mount your node_modules in the docker volumes space. That way it would hide your bind mount.
You need to set the node_modules as a mounted volume in the docker container.
e.g
docker-compose.yml
app:
build: .
command: make run
volumes:
- .:/test
- /test/node_modules
environment:
NODE_ENV: dev
ports:
- "17883:17883"
- "17884:17884"
I've figured out how to do this without a Dockerfile, in case that's useful to anyone...
You can run multiple commands in the docker-compose.yml command line by using sh -c.
my-server:
image: node:18-alpine
build: .
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
working_dir: /usr/src/app
ports:
- "3100:3100"
command: sh -c "npm install -g nodemon && npm install && npm run dev "
environment:
NODE_ENV: development
PORT: 3100

Resources