My goal is to set up configuration for my VS Code Debugger.
A legacy code I have is using docker container to run redis, and gulp task runner to launch an app.
My workflow consists of the following commands that I type in terminals:
docker-compose up which runs redis with db
gulp default starts the app's server
So far I've successfully created config for the gulp task, but still struggling to set up configuration for docker in debugger.
Docker Desktop is installed locally on Windows 10 Pro
Docker version: 2.0.0.0-win81 (29211)
docker file: docker-compose.yml
version: "2"
services:
redis:
container_name: redis
image: redis:latest
ports:
- 7113:6379
mariadb-test:
container_name: mariadb-test
image: wodby/mariadb
ports:
- 6604:3306
environment:
- MYSQL_ROOT_PASSWORD=***
- MYSQL_USER=****_****
- MYSQL_PASSWORD=****
- MYSQL_DATABASE=****
- MYSQL_CHARACTER_SET_FILESYSTEM=utf8mb4
- MYSQL_CHARACTER_SET_SERVER=utf8mb4
- MYSQL_CLIENT_DEFAULT_CHARACTER_SET=utf8mb4
- MYSQL_COLLATION_SERVER=utf8mb4_unicode_ci
- MYSQL_INIT_CONNECT=SET NAMES utf8mb4
Gulp task
gulp.task('default', function (done) {
runSequence('build:server', 'watch', 'start');
});
gulp.task('build:server', function (done) {
var tsProject = tsc.createProject('tsconfig.json');
var tsResult = gulp.src(['server/**/*.ts', 'server/**/*.tsx', '!server/test/**/*'])
.pipe(cache('typescript'))
.pipe(sourcemaps.init())
.pipe(tsProject()).js
.pipe(sourcemaps.mapSources(function (sourcePath, file) {
return sourcePath.replace('../../', '../');
}))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest('dist/server'))
.on('end', done);
});
gulp.task('watch', function () {
gulp.watch(['server/**/*.ts', 'server/**/*.tsx', '!server/desktop/**/*', '!server/test/**/*'], ['compile']).on('change', function (e) {
gutil.log( gutil.colors.blue.bold('[CHANGE] ') + gutil.colors.green(e.path));
});
});
gulp.task('start', function () {
nodemon({
script: 'dist/server/bin.js',
watch: 'dist/',
ext: 'html js',
tasks: []
});
});
My launch.json configuration
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Gulp",
"program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js",
"args": [
"default"
]
},
{
"type": "node",
"request": "attach",
"name": "Docker",
"address": "localhost",
"port": 6379,
"localRoot": "${workspaceFolder}",
"remoteRoot": "/",
}
]
}
All the time I'm getting this error:
Error: Cannot connect to runtime process, timeout after 10000 ms - (reason: Cannot connect to the target: connect ECONNREFUSED 127.0.0.1:6379).
As you don't run your appliaction in docker, you don't need to fiddle with that. However, you will need to add --inspect or --inspect-brk to your gulp task when you start your node process.
I would suggest creating a new debug task to your gulpfile:
gulp.task('debug', function (done) {
runSequence('build:server', 'watch', 'start:debug');
});
gulp.task('start:debug', function () {
nodemon({
script: 'dist/server/bin.js',
watch: 'dist/',
nodeArgs: ['--inspect'] // or --inspect-brk
ext: 'html js',
tasks: []
});
});
then you should be able to debug your code using chrome as can be seen here: https://blog.risingstack.com/how-to-debug-a-node-js-app-in-a-docker-container/
Be advised though that according to this question, you should use nodemon 1.12.7 or above to get this working.
Related
I've this simple code in index.js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.pdf({ path: './prints/test.pdf', format: 'A4' });
await browser.close();
})();
It works with command node index.js.
BUT when I want to run it with pm2
with cmd pm2 start ecosystem.config.js --env=production
ecosystem.config.js
module.exports = {
apps: [
{
name: "print_ca",
script: "index.js",
evn: {
NODE_ENV: "development",
},
env_production: {
NODE_ENV: "production",
},
instances: 1,
exec_mode: "fork",
ignore_watch: ["node_modules", "prints", "storage"],
},
],
};
But shows the error:
I don't know why it happens, with node index.js it works but with PM2 won't work?
The user's right to start the pm2 process is not enough to access the feature file. try to restart the pm2 in service with the admin account
I'm trying to use environment variables on docker only needed for on command. On Mac/Linux I can simple just run token=1234 node command.js and token is available as an environment variable. But when I do this with docker docker exec $CONTAINER nenv token=123 node command.js I get unknown command token=123
I don't use node env,
I recommend to do following:
create config folder
put this in config/index.js
var
nconf = require('nconf'),
path = require('path');
nconf.env().argv();
nconf.file('local', path.join(__dirname, 'config.local.json'));
nconf.file(path.join(__dirname, 'config.json'));
module.exports = nconf;
create files: config/config.json (template of config) and config/config.local.json (copy of template with real configuration)
for example:
{
"app": {
"useCluster": false,
"http": {
"enabled": true,
"port": 8000,
"host": "0.0.0.0"
},
"https": {
"enabled": false,
"port": 443,
"host": "0.0.0.0",
"certificate": {
"key": "server.key",
"cert": "server.crt"
}
},
"env": "production",
"profiler": false
},
"db": {
"driver": "mysql",
"host": "address here",
"port": 3306,
"user": "username here",
"pass": "password here",
"name": "database name here"
},
}
use in beginning of Your app: var config = require('./config');
and use config object whenever You need:
var config = require('./config'),
cluster = require('./components/cluster'),
http = require('http'),
...
...
https = require('https');
cluster.start(function() {
if (config.get('app:http:enabled')) {
var httpServer = http.createServer(app);
httpServer.listen(config.get('app:http:port'), config.get('app:http:host'),
function () {
winston.info('App listening at http://%s:%s', config.get('app:http:host'), config.get('app:http:port'));
});
}
if (config.get('app:https:enabled')) {
var httpsServer = https.createServer({
key: fs.readFileSync(path.join(__dirname, 'certificates', config.get('app:https:certificate:key'))),
cert: fs.readFileSync(path.join(__dirname, 'certificates', config.get('app:https:certificate:cert')))
}, app);
httpsServer.listen(config.get('app:https:port'), config.get('app:https:host'),
function () {
winston.info('App listening at https://%s:%s', config.get('app:https:host'), config.get('app:https:port'));
});
}
});
this example is more accurate way to have environment based configs. for example: config.local.json configuration that will be added to .gitignore and so on...
EDIT caused by my stupidness !
You can't set new env var using docker on an existing docker.
You have to do this when you build it (using Dockerfile or docker-compose), or when you run it (using docker run $CONTAINER -e "name=value" command).
Even if you need to simply retrieve certain configurations from the command (at docker run time) you can do it simply by switching from node env (process.env) to argv usage.
Such casers are not uncommon (docker-compose), and could be done in very easy way.
npm install yargs --save
run code with docker run or docker exec:
docker exec $CONTAINER node command.j --token 123
then in code:
const argv = require('yargs').argv;
...
let boo = do.something(argv.token);
My jasmine-node tests are executed twice.
I run those test from Grunt task and also from Jasmine command. Result is the same my tests are run twice.
My package.json :
{
"name": "test",
"version": "0.0.0",
"dependencies": {
"express": "4.x",
"mongodb": "~2.0"
},
"devDependencies": {
"grunt": "~0.4.5",
"grunt-jasmine-node":"~0.3.1 "
}
}
Here is my Gruntfile.js extract :
grunt.initConfig({
jasmine_node: {
options: {
forceExit: true,
match: '.',
matchall: true,
extensions: 'js',
specNameMatcher: 'spec'
},
all: ['test/']
}
});
grunt.loadNpmTasks('grunt-jasmine-node');
grunt.registerTask('jasmine', 'jasmine_node');
One of my test file :
describe("Configuration setup", function() {
it("should load local configurations", function(next) {
var config = require('../config')();
expect(config.mode).toBe('local');
next();
});
it("should load staging configurations", function(next) {
var config = require('../config')('staging');
expect(config.mode).toBe('staging');
next();
});
it("should load production configurations", function(next) {
var config = require('../config')('production');
expect(config.mode).toBe('production');
next();
});
});
I have 2 test files for 4 assertions
Here is my prompt :
grunt jasmine
Running "jasmine_node:all" (jasmine_node) task
........
Finished in 1.781 seconds
8 tests, 8 assertions, 0 failures, 0 skipped
Have you got any idea ?
All credit to 1.618. He answered the question here: grunt jasmine-node tests are running twice
This looks likes some buggy behaviour. The quick fix is to configure jasmine_node in your Gruntfile like this:
jasmine_node: {
options: {
forceExit: true,
host: 'http://localhost:' + port + '/',
match: '.',
matchall: false,
extensions: 'js',
specNameMatcher: '[sS]pec'
},
all: []
}
The key is the all parameter. The grunt plugin is looking for files with spec in the name. For some reason, it looks in the spec/ directory and everywhere else. If you specify the spec directory, its files get picked up twice. If you don't specify, it only gets set once, but then you can't put spec in any of your non-test filenames.
How to run two script at once with npm run?
First of all I know grunt or gulp but I want to make it without another js modules.
To make this I have this script:
"scripts": {
"start": "node ./node/www",
"nodemon": "./node_modules/.bin/nodemon node/www.js -i './e2e-tests/**' -i './node_modules/**' -i '.idea/**' -i './node/log/**' -w './node/server/**/*' -V -L",
"nodeInspector": "./node_modules/.bin/node-inspector --save-live-edit=true",
"debug": "node-debug ./node/www.js",
"ins": "npm run nodeInspector & npm run debug"
}
I want to run with npm run ins but it only fires node-inspector.
It is not possible to run both commands. They each need their own console
If node-debug comes from node-inspector package, then you don't need to start a new node-inspector instance, node-debug will start it automatically for you.
This is what node-debug performs under the hood (source code):
Run node-inspector.
Run the supplied script in debug mode
Open the user's browser, pointing it at the inspector.
In fact, running both node-inspector and node-debug will not work as intended, as the second node-inspector instance won't be able to attach to the same port where the first instance already listens.
I couldn't make it happen on one line that's why I changed to grunt with concurrent:
module.exports = function(grunt) {
grunt.initConfig({
concurrent: {
options: {
limit: 3,
logConcurrentOutput: true
},
debug: {
tasks: ['node-inspector', 'nodemon:debug'],
options: {
logConcurrentOutput: true
}
}
},
nodemon: {
dev: {
script: "node/www.js",
options: {
ignore: ['node/public/**'],
callback: function (nodemon) {
nodemon.on('log', function (event) {
console.log(JSON.stringify(event));
});
// opens browser on initial server start
nodemon.on('config:update', function () {
console.log("nodemon config:update oldu");
// Delay before server listens on port
setTimeout(function() {
require('open')('http://localhost:3000');
}, 1000);
});
// refreshes browser when server reboots
nodemon.on('restart', function () {
// Delay before server listens on port
setTimeout(function() {
//require('fs').writeFileSync('.rebooted', 'rebooted');
}, 1000);
});
}
}
},
debug: {
script: './node/www.js',
options: {
ignore: ['node/log/*.log','node/public/**','node/views/**','doc/**','e2e-tests/**','.idea'],
callback: function (nodemon) {
nodemon.on('log', function (event) {
console.log("Nodemon debug callback fonksiyonu nodemon.onLog olayı");
});
// opens browser on initial server start
nodemon.on('config:update', function () {
console.log("Nodemon debug callback fonksiyonu nodemon.onConfig:Update olayı");
// Delay before server listens on port
setTimeout(function() {
require('open')('http://localhost:3000');
require('open')('http://localhost:1337/debug?port=5858');
}, 1000);
});
// refreshes browser when server reboots
nodemon.on('restart', function () {
console.log("Nodemon debug callback fonksiyonu nodemon.onRestart olayı");
// Delay before server listens on port
setTimeout(function() {
//require('fs').writeFileSync('.rebooted', 'rebooted');
}, 1000);
});
},
nodeArgs: ['--debug'],
watch: ['Gruntfile.js', 'node/server', 'package.json']
}
}
},
'node-inspector': {
custom: {
options: {
'web-port': 1337,
'web-host': 'localhost',
'debug-port': 5857,
'save-live-edit': true,
'no-preload': true,
'stack-trace-limit': 4,
'hidden': ['node_modules']
}
}
}
});
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
// Çalışması test edildi ve iki pencerede hem test hem uygulama açıyor.
grunt.registerTask('nodemon-debug', ['concurrent:debug']);
};
I managed to run node-inspector and nodemon from a script using concurently
https://www.npmjs.com/package/concurrently
"dev": "npm install && concurrently \"node-inspector --web-port 9090\" \"nodemon --debug .\""
So, I have the grunt file below. I'm wanting to add a task that will start my node app and watch for changes in a directory and restart. I have been using supervisor, node-dev (which are great) but I want to run one command and start my whole app. There has got to be a simple way to do this, but I'm just missing it. It is written in coffeescript as well (not sure if that changes things)...
module.exports = function(grunt) {
grunt.initConfig({
/*exec: {
startApi: {
command: "npm run-script start-api"
}
},*/
//static server
server: {
port: 3333,
base: './public',
keepalive: true
},
// Coffee to JS compilation
coffee: {
compile: {
files: {
'./public/js/*.js': './src/client/app/**/*.coffee'
},
options: {
//basePath: 'app/scripts'
}
}
},
mochaTest: {
all: ['test/**/*.*']
},
watch: {
coffee: {
files: './src/client/app/**/*.coffee',
tasks: 'coffee'
},
mochaTest: {
files: 'test/**/*.*',
tasks: 'mochaTest'
}
}
});
grunt.loadNpmTasks('grunt-contrib-coffee');
grunt.loadNpmTasks('grunt-mocha-test');
//grunt.loadNpmTasks('grunt-exec');
grunt.registerTask( 'default', 'server coffee mochaTest watch' );
};
As you can see in the comments, I tries grunt-exec, but the node command stops the execution of the other tasks.
You can set grunt to run default task and the watch task when you start your node app:
in app.js
var cp = require('child_process');
var grunt = cp.spawn('grunt', ['--force', 'default', 'watch'])
grunt.stdout.on('data', function(data) {
// relay output to console
console.log("%s", data)
});
Then just run node app as normal!
Credit