Categories
Node.js Tips

Node.js Tips — Modules, Request Bodies, Reading Lines, and More

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

How to Include Functions from Other Files

We can include functions from other files if we export the function from a module and then import them.

For example, we can write:

fns.js

module.exports = {
  foo() {
    //...
  }
};

module.exports indicates that we’re exporting the properties inside.

Then we can import it by writing:

const `fns` = require('./`fns`');
`fns.foo();`

We use the require keywords to import the fns.js module.

We don’t need the file extension.

Using Node.js require vs. ES6 import/export

require is the most versatile way to import modules and it’s supported by all versions of Node.

ES6 imports and exports are supported natively only by the most recent versions of Node.

Therefore, require is still the best bet until our apps are running on the latest version of Node.

Sending Command-Line Arguments to npm script

We can send command line arguments to an NPM script by using the -- characters.

For example, if we have the following in package.json :

"scripts": {
  "server": "node server.js"
}

Then we can run:

npm run server -- --port=1234

Retrieve POST Query Parameters in an Express App

We can retrieve POST query parameters in an Express app by installing the body-parser package.

To install it, we run:

npm install --save body-parser

For example, we can write:

const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

bodyParser.json() will parse JSON payloads.

And bodyParser.urlencoded will parse URL encoded payloads.

‘Can’t set headers after they are sent to the client’ Error

We should make sure that we don’t send a response more than once in our app.

For instance, we should write:

const foo = (request, response, next) => {
  request.params = {
    a: "b"
  };
  next();
};

const bar = function(request, response, next) => {
  response.setHeader("Content-Type", "text/html");
  response.write("hello world");
  response.end();
};

app.use(foo);
app.use(bar);

Anything that modifies the response should be placed last.

This way, we don’t send the response more than once.

Anything that calls next shouldn’t modify the response so that we won’t call any middleware that does send the response after it.

Convert an Existing Callback API to Promises

We can convert any async callback to a promise with the Promise constructor.

For instance, we can write:

const run = () => {
  return new Promise((resolve, reject) => {
    //...
    resolve();
  });
}

We return a promise in our run function so we can use it with async and await or then .

Also, we can use the util package’s promisify method to convert functions that take Node style callbacks to return a promise.

For instance, we can write:

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

(async () => {
  const data = await `readFile('/foo.txt');
  //...
})();`

We convert the async readFile method to a promise by using the util.promisify method.

Then we get the data from reading the file with await .

Read a File One Line at a Time

To read a file one line at a time, we can use the readline module.

For example, we can write:

const fs = require('fs');
const readline = require('readline');

const readLineByLine = async () => {
  const fileStream = fs.createReadStream('foo.txt');

  const rl = readline.createInterface({
    input: fileStream,
    crlfDelay: Infinity
  });

  for await (const line of rl) {
    console.log(line);
  }
}

readLineByLine();

We call createInterface to get an iterator with the lines, then we use the for-await-of loop to loop through the lines.

Also, we can create a read stream by writing:

const readline = require('readline');

readline.createInterface({
  input: require('fs').createReadStream('file.in')
});

lineReader.on('line', (line) => {
  console.log(line);
});

We use the createInterface like the last example, but we call on to listen to the line event which has the line that’s read.

Conclusion

We can export and import files to include functions from other JavaScript files.

Reading a file one line at a time can be done with the readline library.

Also, we should make sure that we don’t send a response more than once in our Express app.

The body-parser package lets us parse request payloads in an Express app.

Categories
Node.js Tips

Node.js Tips — Templates, Queries, Dates, and Memory

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Get Data from fs.readFile

We can call the readFile method from the fs module to tread files.

For instance, we can write:

fs.readFile('./foo.txt', (err, data) => {
  if (err) {
    throw err;
  }
  console.log(data);
});

We pass in the path and then read it as a binary file.

data has the file content and err is the error object that’s set when an error is encountered.

There’s also the fs.readFileSync method:

const text = fs.readFileSync('./foo.txt', 'utf8');
console.log(text);

Get a URL Parameter in Express

To get a URL parameter in an Express app, we can use the req.params property to get the URL parameter.

For instance, we can write:

app.get('/tags/:tagId', (req, res) => {
  res.send(req.params.tagId);
});

Then if we make a GET request to /tags/2 , we get 2 as the value of req.params.tagId .

To get a value from a query parameter, we can use the req.query property:

app.get('/foo', (req, res) => {
  res.send(req.query.tagId);
});

Then if we make a request to /foo?tagId=2 , req.query.tagId would be 2.

Render Basic HTML View

We can render HTML by using include to include HTML file in our Jade view.

For instance, we can write in views/index.jade:

include plainHtml.html

Then in views/plainHtml.html , we can write normal HTML”

<!DOCTYPE html>
...

And we render index.jade with:

res.render(index);

NodeJS Support for import/export ES6 (ES2015) Modules

If our app is running on Node 13.2.0 or above, we can enable ES6 module support by adding the following to package.json :

{
  "type": "module"
}

With Node 13.1.0 or below, we can write:

node -r esm main.js

We turn on ES module support by using esm .

We just run npm i esm to add esm to our Node project.

Use underscore.js as a Template Engine

We can use the template method to pass in our HTML template string.

For instance, we can write:

const template  = _.template("<h1>hello <%= name %></h1>");

template is a function that takes an object with the placeholders.

Then name is the placeholder that we can pass in.

For instance, we can write:

const str = `template({ name: 'world' });`

Then str would be '<h1>hello world</h1>’ .

<%= %> means to print some value in the template.

<% %> executes some code.

<%- %> prints some values with the HTML escaped.

Start Script Missing Error When Running npm start

To solve this error, we can add the start script to package.json by putting it in the scripts section.

For instance, we can write:

"scripts": {
  "start": "node app.js"
}

The script with the key start will run when we run npm start .

Node.js Heap Out of Memory

We can increase the memory limit of Node apps by setting the max-old-space-size option.

For instance, we can write:

node --max-old-space-size=2048 app.js

to increase the memory limit to 2 GB.

We can also set it in the NODE_OPTIONS environment variable:

export NODE_OPTIONS=--max_old_space_size=2048

Callback After All Asynchronous forEach Callbacks are Completed

We can use the for-await-of loop to loop through promises.

For instance, we can write:

const get = a => fetch(a);

const getAll = async () => {
  const promises = [1, 2, 3].map(get);

  for await (const item of promises) {
    console.log(item);
  }
}

This will run each promise sequentially with a loop.

This is available since ES2018.

Format a UTC Date as a YYYY-MM-DD hh:mm:ss String

We can use the toISOString method to format a Date instance into a date string in the ‘YYYY-MM-DD hh:mm:ss’ format.

For instance, we can write”

const str = new Date()
  .toISOString()
  .`replace(/T/, ' ')
  .replace(/..+/, '');`

We replace the T with an empty string, and replace the text after the dot with an empty string.

Then we get '2020–06–04 16:15:55' as the result.

Conclusion

Underscore has a template method.

readFile can read files.

We can get query parameters in Express.

The memory limit of Node apps can be increased.

Jade templates can include HTML partial views.

Categories
Node.js Tips

Node.js Tips — Environment Variables, Downloads, DNS, and More

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Node.js Require All Files in a Folder

We can export all modules in a folder by creating a module that exports all the modules.

Then we can import them all at once.

For instance, we can write:

index.js

exports.foo = require("./routes/foo.js");
exports.bar= require("./routes/bar.js");

app.js

const routes = require("./routes");

We can also write:

const fs = require("fs");
const normalizedPath = require("path").join(__dirname, "routes");

fs.readdirSync(normalizedPath).forEach((file) => {
  require(`./routes/${file}`);
});

Stringify an Error

We can log an error by looping through the properties of an object.

For instance, we can write:

const error = new Error('error');
const propertyNames = Object.getOwnPropertyNames(error);

for (const prop of propertyNames) {
  const descriptor = Object.getOwnPropertyDescriptor(error, prop);
  console.log(prop, descriptor);
}

We use the Object.getOwnPropertyNames method to get the properties of the error object.

Then we get the descriptors of each property.

Difference Between “process.stdout.write” and “console.log” in Node.js

console.log calls process.stdout.write with formatted output.

The code for console.log is just:

console.log = function (d) {
  process.stdout.write(d + 'n');
};

They are pretty much equivalent except for the extra line break.

Set NODE_ENV to production/development in Mac OS or Windows

We can use the export command to set environment variables in Mac OS.

For instance, we can set the NODE_ENV by running:

export NODE_ENV=production

In Windows, we can use the SET command:

SET NODE_ENV=production

We can also set process.env.NODE_ENV directly:

process.env.NODE_ENV = 'production';

We can set the environment when we run the file by running:

NODE_ENV=production node app.js

It also works in the package.json scripts :

{
  ...
  "scripts": {
    "start": "NODE_ENV=production node ./app"
  }
  ...
}

Using require in Express Templates

require is included with CommonJS.

It’s not a part of browser-side JavaScript natively.

To include JavaScript files, we can use the script tag.

Also, we can use CommonJS module.

Or we can use async modules.

Browserify, Webpack, and Rollup can bundle modules into build artifacts usable by the browser.

We can also use ES6 modules natively in browsers with the type attribute set to module .

For instance, we can write:

script.js

export const hello = () => {
  return "Hello World";
}

We can then include script.js by writing:

<script type="module" src="script.js"></script>

Measure the Execution Time of JavaScript Code with Callbacks

We can use the console.time and console.timeEnd methods to measure the time of a script.

For instance, if we have:

for (let i = 1; i < 10; i++) {
  const user = {
    id: i,
    name: "name"
  };
  db.users.save(user, (err, saved) => {
    if(err || !saved) {
      console.log("error");
    } else {
      console.log("saved");
    }
  });
}

We can call the methods by writing:

console.time("save");

for (let i = 1; i < 10; i++) {
  const user = {
    id: i,
    name: "name"
  };
  db.users.save(user, (err, saved) => {
    if(err || !saved) {
      console.log("error");
    } else {
      console.log("saved");
    }
    console.timeEnd("save");
  });
}

We’ve to pass in the same string to time and timeEnd .

Download a File from NodeJS Server Using Express

We can download a file with the res.download method in an Express route.

For instance, we can write:

const path = reqyire('path');

app.get('/download', (req, res) => {
  const file = path.join(`${__dirname}, 'folder', 'img.jpg');
  res.download(file);
});

We just get the path and pass it to res.download .

URl Encode a String in Node.js

We can URI encode a string in Node.jhs with the querystring module.

For instance, we can write:

const querystring = require("querystring");
const result = querystring.stringify({ text: "hello world"});

Then we get 'text=hello%20world’ for result .

Get Local IP Address in Node.js

We can get a local IP address in a Node app with the dns module.

For instance, we can write:

const dns = require('dns');
const os = require('os');

dns.lookup(os.hostname(), (err, addr, fam) => {
  console.log(addr);
})

We call lookup with the hostname to get the IP address from the hostname.

Then addr has the IP address.

Conclusion

We can get the IP address with the dns module.

console has methods to let us measure the timing of code.

We can require files dynamically.

Environment variables can be set dynamically.

Categories
Node.js Tips

Node.js Tips — File Operations, Command Line Arguments, and More

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Pass Command-Line Arguments to a Node.js Program

We get command line arguments by using the process.argv property.

It’s an array with all the arguments including node and the script name.

'node' is always the first entry.

The script name is the 2nd entry.

The rest of the arguments are the remaining entries.

For instance, if we have:

node foo.js one two=three four

Then node is the first entry of process.argv , foo.js is the 2nd, one is the 3rd, and so on.

Writing files in Node.js

We can use the writeFile method to write a file in a Node app.

For instance, we can write:

const fs = require('fs');

fs.writeFile("/foo.txt", "hello world!", (err) => {
  if (err) {
    return console.log(err);
  }
  console.log("file saved");
});

We call writeFile to write the file.

The first argument is the path to the file.

The 2nd is the content of the file.

The callback is called when the file writing process ends.

err is the error object and it’s defined when an error is encountered.

There’s also a synchronous version call writeFileSync .

We can use it by writing:

fs.writeFileSync('/foo.txt', 'hello world');

The first argument is the file path.

The 2nd is the content.

How to Debug Node.js Applications

We can use the node-inspector package to debug Node apps.

We can install it by running:

npm install -g node-inspector

to install it globally.

Then we run node-debug app.js to run it with node-inspector which lets us debug it with breakpoints, profiling, etc.

We can also run node inspect app.js to run app.js with the debugger.

Read Environment Variables in Node.js

We can read environment variables in Node apps by using the process.env object.

For instance, if we have the environment variable FOO , we can write:

process.env.FOO

Remove Empty Elements from an Array in Javascript

To remove empty from a JavaScript array, we can use the filter method.

For example, we can write:

const arr = [0, 1, null, undefined, 2,3,,,,6];
const filtered = arr.filter((el) => (el !== null || typeof el !== 'undefined'));

This will return an array created from arr with all the null and undefined removed.

Using async/await with a forEach loop

We can use async and await with the for-of loop.

For instance, we can write:

const printFiles = async (filePaths) => {
  for (const file of filePaths) {
    const contents = await fs.readFile(file, 'utf8');
    console.log(contents);
  }
}

We use the promisified version of readFile to read the file inside each iteration of the for-of loop.

To run promises in parallel, we can use the Promise.all method.

For instance, we can write:

const printFiles = async (filePaths) => {
  await Promise.all(filePaths.map(async (file) => {
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  }));
}

We call map to filePaths to map the paths to promises.

Then we call Promise.all on the array of promises.

Get a List of the Names of All Files Present in a Directory in a Node App

We can get a list of names of all files in a directory by using the readdir or readdirSync method.

For example, we can write:

const fs = require('fs');

fs.readdir('/tesrDir', (err, files) => {
  files.forEach(file => {
    console.log(file);
  });
});

files have the array of file strings, buffer, or directory entries.

To read a directory synchronously, we can write:

const fs = require('fs');

fs.readdirSync('/testDir').forEach(file => {
  console.log(file);
});

We read a directory synchronously.

Parse JSON with Node.js

We can require JSON files or parse them with JSON.parse .

For example, we can write:

const config = require('./config.json');

or:

const config = require('./config');

The extension is optional.

Also, we can use JSON.parse to parse JSON strings.

Conclusion

We can get command-line arguments with process.argv .

Environment variables are read into the process.env object.

require can be used to import JSON files.

The fs module has methods to read and write files.

The for-of loop can run promises sequentially.