Wednesday, March 4, 2020

How to fix ReferenceError: function is not defined Node.js?

I just encountered an issue that function is not defined. when i checked my code. the function did exist in the script file.

ReferenceError: fullUrl is not defined
    at Command.program.command.description.action (/mnt/c/node/esclu/index.js:22:17)
    at Command.listener (/mnt/c/node/esclu/node_modules/commander/index.js:301:8)
    at Command.emit (events.js:198:13)
    at Command.parseArgs (/mnt/c/node/esclu/node_modules/commander/index.js:615:12)
    at Command.parse (/mnt/c/node/esclu/node_modules/commander/index.js:458:21)
    at Object.<anonymous> (/mnt/c/node/esclu/index.js:25:9)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)


the root cause of this issue is that the order of the defined function is really matter in Node.js

i had to move this function definition to the location after the require lines.


'use strict';

const fs=require('fs');
const request=require('request');
const program =require('commander');
const pkg=require('./package.json');

const fullUrl=(path='')=>{
    let url=`http://${program.host}:${program.port}`;
    if(program.index){
        url +=program.index +'/';
        if(program.type){
            url +=program.type +'/';
        }
    }
    return urlpath.replace(/^\/*/'');
}

program
.version(pkg.version)
.description(pkg.description)
.usage('[options] <commander> [...]')
.option('-o, --host <hostname>','hostname [hostname]','localhost')
.option('-p, --port <number>','port number [9200]''9200')
.option('-j, --json','format output as json')
.option('-i, --index <name>','which index to use')
.option('-t, --type <name>''default type for bulk opertions');

program
.command('url [path]')
.description('generate the url for the options adn apth (default is /)')
.action((path='/')=>{
    console.log(fullUrl(path));
});

program.parse(process.argv);

if(!program.args.filter(arg=> typeof arg=='object').length){
    program.help();
}



Tuesday, March 3, 2020

how to use Chrome DevTools to debug Node.js Code in development?

it should a very interesting topic for debugging the Node.js Code with Chrome.


1. you must have mocha package install in your node.js project.

npm install --save --save-exact mocha@2.47.5

after the installation, you will find this package in the package.json file.

"devDependencies": {
    "chai""3.5.0",
    "mocha""2.4.5"
  },

2. set up the test run command in the scripts section

 "scripts": {
    "test:debug""node --inspect node_modules/mocha/bin/_mocha --watch --no-timeouts"
  },

3. execute npm run test:debug to generate a web socket that Chrome can connect to for debugging.

PS C:\node\databases> npm run test:debug

> databases@1.0.0 test:debug C:\node\databases
> node --inspect node_modules/mocha/bin/_mocha --watch --no-timeouts

Debugger listening on ws://127.0.0.1:9229/433a7d4f-e829-47e0-a4b4-d6f6f87df9f0
For help, see: https://nodejs.org/en/docs/inspector



  parseRDF
    √ should be a function
    √ should parse RDF content


  2 passing (52ms)



4. Launch the Chrome browse and navigate to Chrome//inspect, then click on "Open dedicated DevTools for Node" then click on the inspect link to launch the chrome DevTool.









5. click on the source tab, then navigate to the filesystem. click on the add folder button to add your source code folder. interesting, after you complete this step. you have to close the  DevTools window and click on the inspect link again to force the breakpoint get hitting.









you have to click on the allow button in order to your source code.





6 set a breakpoint on the source code that you want to debug, then open a new terminal in visual studio code to run touch yourJavscript.js.

7. the breakpoint will be hit immediately, you can start to step through your code and debug it.




How to fix ZEROMQ ipc issue in windows 10 for node.js development?

i have a line to connect to the DEALER socket.

const responder=zmq.socket('rep').connect('ipc://filer.dealer.ipc');

when i run the app. the error comes up immediately

 this._zmq.connect(addr);
            ^
Error: Protocol not supported
    at exports.Socket.Socket.connect (C:\node\microservices\node_modules\zeromq\lib\index.js:519:13)
    at Object.<anonymous> (C:\node\microservices\zmq-filer-rep-cluster.js:26:39)
    at Module._compile (internal/modules/cjs/loader.js:1139:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1159:10)
    at Module.load (internal/modules/cjs/loader.js:988:32)
    at Function.Module._load (internal/modules/cjs/loader.js:896:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47

obviously IPC is for Linux and Unix in process communication. windows did support this kind of communication too. however windows use INPROC instead.

after i changed my code as following, the error had been fixed and running

const responder=zmq.socket('rep').connect('inproc://filer.dealer.ipc');


how to fix "TypeError: zmq.socket is not a function" with Node.js in Windows 10?

i just try to use ZEROMQ for a simple publish/subscribe Message passing app.

when i run the app with Node myApp.js. the app thrown an exception

C:\node\microservices\zmq-watch-pub.js:6
const publisher=zmq.socket('pub');     

TypeError: zmq.socket is not a function
    at Object.<anonymous> (C:\node\microservices\zmq-watch-pub.js:6:21)
    at Module._compile (internal/modules/cjs/loader.js:1139:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1159:10)
    at Module.load (internal/modules/cjs/loader.js:988:32)
    at Function.Module._load (internal/modules/cjs/loader.js:896:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47


 I am running in the windows 10 environment and i install zeromq@4.3.2

 "dependencies": {
    "zeromq""4.3.2"
  }

 i already encounter an error during the npm install  zeromq@4.3.2, i have to install verison 5 to avoid the error   npm install  zeromq@5

here is my current zeromq package

 "dependencies": {
    "zeromq""^5.2.0"
  }

Now i can launch the app and start monitoring the file change.

PS C:\node\microservices> node zmq-watch-pub.js target.txt
Listening for zmq subscribers....

Monday, March 2, 2020

how to write a test case that emit a close event to process the buffer after the eventemitter going offline?

Today i am continuing my learning Journey with "Node.js 8 The Right Way Practical, Server-Side Javvascript that Scales".

here is the challenge question that required to write a case against eventemitter sends JSON causing the error. follow by the close event. the eventemitter will emit a close event before going offline. the client will listen for the close event, then process the buffer data after error had been encountered.

here is the line to handle the close event that processed the data left in the buffer after throwing an error in the client.

 stream.on('close', ()=>{
            this.emit('message',JSON.parsebuffer));
        })

the following line will set up the test case. stream emit the Json Data without newline, following by emitting a close event.

 it('test case on close event',done=>{
        client.on('message'message=> {
            console.log(message);
            assert.deepEqual(message, {foo: 'bar'});
            done();
        });
        stream.emit('data','{"foo": "bar"}');
        stream.emit('close');
    });

LDJClient.js

'use strict';
const EventEmitter=require('events').EventEmitter;

class LDJClient extends EventEmitter {
    constructor(stream){
        super();
        let buffer='';
        stream.on('data',data=>{
            console.log(data);
            buffer +=data;
            let boundary=buffer.indexOf('\n');
            while(boundary !=-1){
                const input=buffer.substring(0boundary);
                buffer=buffer.substring(boundary+1);
                this.emit('message'JSON.parse(input));
                boundary=buffer.indexOf('\n');
            }
        });
        stream.on('close', ()=>{
            this.emit('message',JSON.parsebuffer));
        })
    }
    static connect(stream){
        return new LDJClient(stream);
    }
}

module.exports=LDJClient;

test-ldj-client.js

'use strict';
const assert=require('assert');
const EventEmitter=require('events').EventEmitter;
const LDJClient=require('../lib/ldj-client.js');

describe('LDJClient', ()=>{
    let stream=null;
    let client=null;

    beforeEach(()=>{
        stream=new EventEmitter();
        client=new LDJClient(stream);
    });
    it('should emit a message event for a single data event'done=> {
        client.on('message'message=> {
            assert.deepEqual(message, {foo: 'bar'});
            done();
        });
        stream.emit('data','{"foo": "bar"}\n');
        //stream.emit('data','{"foo":');
        //process.nextTick(()=> stream.emit('data', '"bar"}\n'));
    });

    it('test case on close event',done=>{
        client.on('message'message=> {
            console.log(message);
            assert.deepEqual(message, {foo: 'bar'});
            done();
        });
        stream.emit('data','{"foo": "bar"}');
        stream.emit('close');
    });
});


the output of test case is succeed. cheers





How would you pass an arbitrary number of additional parameters from process.agrv to the spwaned process?

I am following the book "Node.js 8 the right way"

here is a question to expand the functionality from book. How would you pass an arbitrary number of additional parameters from process.agrv to the spwaned process?

here is original code to monitor the file changes with command being hard code.

'use strict';
const fs=require('fs');
const spawn=require('child_process').spawn;
const filename=process.argv[2];

if(!filename){
    throw Error('A file to watch must be specified');
}
fs.watchFile(filename, ()=>{
    const ls=spawn('ls',['-l''-h'filename]);
    let output='';
    ls.stdout.on('data'chunk=>output +=chunk);
    ls.on('close', ()=>{
        const parts=output.split(/\s+/);
        console.log(parts[0], parts[4], parts[8]);
    })
});

console.log('Now watching target.txt for change.....');


 Now we can change the code handle arbitrary number of parameters. here is the spawn method child_process.spawn(command[, args][, options). we need to use an array to build the argument portion.

let options=[];
for (var i = 4i < process.argv.lengthi++) {
    options.push(process.argv[i]);
}
options.push(filename);

We can integrate the above code into our new program, then the program can accept any number of parameters. 

node watcher-spawn-cmd.js target.txt ls -l -h

 node watcher-spawn-cmd.js target.txt ls -l -h -s



'use strict';
const fs=require('fs');
const spawn=require('child_process').spawn;
const filename=process.argv[2];
const commandname=process.argv[3];

let options=[];
for (var i = 4i < process.argv.lengthi++) {
    options.push(process.argv[i]);
}
options.push(filename);

if(!filename){
    throw Error('A file to watch must be specified');
}

fs.watchFile(filename, ()=>{
    const ls=spawn(commandname, options);  
    let output='';
    ls.stdout.on('data'chunk=>output +=chunk);
    ls.on('close', ()=>{
        const parts=output.split(/\s+/);
        console.log(parts[0], parts[4], parts[8]);
    })
});

console.log('Now watching target.txt for change.....');








Sunday, March 1, 2020

Node.JS development quick tips

1. use the backtick character (`) for string interpolation
const mystring='Dan Test'

console.log(`my string value is ${mystring}`);

output is "my string value is Dan Test"

2. @hapi/joi is great library to support JavaScript object validation.

you can find the example in the github.

https://github.com/hapijs/joi/blob/master/API.md

3.  fs.watch event will trigger twice when you change the file in the windows development environment. However fs.watchFile only fire once.

trigger twice

fs.watch(filename, ()=>console.log(`File ${filename} changed`));

fire properly

fs.watchFile(filename, ()=>{
    const ls=spawn('ls',['-l''-s'filename]);
    ls.stdout.pipe(process.stdout);
});

4. keyword const is for variable that has value assignment on declaration and will not change after the declaration. keywork let will  allow variable to be assigned a value more than once.

5. it is the best practice to use try and catch to handle the exception, since the program will be halt by uncaught exception.

6. const fs=require('fs') which will reference the file system library. node.js use require to import library.

7. use npm init -y to create a default package.json file for the project.

8. use npm install --save-dev( for project level development) --save-exact(will install the specified version only).

9. use + (unary plus to cast the result as a number)
book.id=+$('pgterms\\:ebook').attr('rdf:about').replace('ebooks/','');

10. Morgan module is great logging utility for debugging.

npm install morgan@latest to add this module to the project

the output will display as below

GET /hello/:Danny 200 9.785 ms - 18
GET /favicon.ico 404 2.592 ms - 24
GET /hello/:Danny 304 1.844 ms - -


11. use app.use() to specify middleware for the app.

app.use(morgan('dev')) to add morgan logging middleware to the app. 

12. use curl -i url to show the response body and  http header as well.

13. curl -s url will use the slient mode and only body will be displayed.