1. Require Function
    In Node.js, the require function is used to include modules that exist in separate files. It is one of the key components of Node.js, allowing you to structure your application into reusable pieces of code. To include a module in your Node.js application, you use the require function followed by the path to the module.

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

    How require Works
    i) Loading Built-in Modules: Node.js comes with several built-in modules, such as fs (file system), http, path, etc. You can load these by simply using their names.

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

    ii) Loading Local Modules: For your own modules, you need to specify the relative or absolute path to the module file. The path should start with ./ for relative paths or / for absolute paths.

     const myModule = require('./myModule'); // Relative path
     const anotherModule = require('/path/to/module'); // Absolute path
    

    iii) Loading Node Modules: If you're using third-party modules that you've installed via npm (Node Package Manager), you can require them by their package name.

     const express = require('express');
     const lodash = require('lodash');
    

    iv) Module Caching: When a module is loaded for the first time, Node.js caches the module. This means that subsequent calls to require for the same module will return the cached version, not a newly created one. This is done for performance reasons and to ensure that any state maintained by the module is preserved across require calls.
    v) Exports: A module exports its functionality by adding properties to the module.exports object. This allows the module to expose functions, objects, or values to other modules that require it.

     // myModule.js
     function greet(name) {
         return `Hello, ${name}!`;
     }
     module.exports = greet;
    
     // In another file
     const greet = require('./myModule');
     console.log(greet('World')); // Outputs: Hello, World!
    

    If you want to export multiple functions from the same file, you can use following code.

     // myModule.js
     function hello(name) {
         return `Hello, ${name}!`;
     }
     function welcome(name) {
         return `Welcome, ${name}!`;
     }
     module.exports = { hello, welcome };
    
     // In another file
     const greet = require('./myModule');
     console.log(greet.hello('World')); // Outputs: Hello, World!
     console.log(greet.welcome('World')); // Outputs: Welcome, World!
    
  2. Core Modules
    Node.js core modules are built-in modules that come with Node.js out of the box. These modules provide essential functionality for building server-side and network applications. Here are some of the key core modules in Node.js,
    i) http
    Used to create an HTTP server.

    Handles HTTP requests and responses.

    Example: http.createServer().

     const http = require('http');
    
     const server = http.createServer((req, res) => {
         res.statusCode = 200;
         res.setHeader('Content-Type', 'text/plain');
         res.end('Hello, world!\n');
     });
    
     server.listen(3000, '127.0.0.1', () => {
         console.log('Server running at http://127.0.0.1:3000/');
     });
    

    ii) fs
    Provides an API for interacting with the file system.
    Methods for reading, writing, updating, and deleting files.
    Example: fs.readFile(), fs.writeFile().

     const fs = require('fs');
    
     // Reading a file
     fs.readFile('example.txt', 'utf8', (err, data) => {
         if (err) {
             console.error(err);
             return;
         }
         console.log(data);
     });
    
     // Writing to a file
     fs.writeFile('example.txt', 'Hello, world!', (err) => {
         if (err) {
             console.error(err);
             return;
         }
         console.log('File written successfully');
     });
    

    iii) buffer
    Provides a way to handle binary data.
    Useful for handling streams of binary data such as TCP streams.
    Example: Buffer.from(), Buffer.alloc().

     const buf = Buffer.from('hello world', 'utf8');
    
     console.log(buf.toString('hex'));
     console.log(buf.toString('base64'));
    

    iv) url
    Utilities for URL resolution and parsing.
    Methods to parse URL strings and resolve URLs.
    Example: url.parse(), url.format().

     const url = require('url');
    
     const myUrl = new URL('https://example.com:8000/path/name?foo=bar#baz');
    
     console.log(myUrl.hostname); // 'example.com'
     console.log(myUrl.pathname); // '/path/name'
     console.log(myUrl.searchParams.get('foo')); // 'bar'
    

    v) events
    Provides an event-driven architecture.
    Allows creation and handling of custom events.
    Example: events.EventEmitter.

     const EventEmitter = require('events');
    
     class MyEmitter extends EventEmitter {}
    
     const myEmitter = new MyEmitter();
     myEmitter.on('event', () => {
         console.log('An event occurred!');
     });
    
     myEmitter.emit('event');
    

    vi) utils
    Utilities for various types of operations.
    Methods for formatting strings, inspecting objects, etc.
    Example: util.format(), util.inspect().

     const util = require('util');
    
     const debuglog = util.debuglog('foo');
     debuglog('Hello from foo [%d]', 123);
    
     const obj = { name: 'Alice', age: 25 };
     console.log(util.inspect(obj));
    

    vii) stream
    Provides an API for working with streaming data.
    Classes for readable, writable, duplex, and transform streams.
    Example: stream.Readable, stream.Writable.

     const { Readable } = require('stream');
    
     const inStream = new Readable({
         read(size) {
             this.push('Hello, ');
             this.push('world!');
             this.push(null);
         }
     });
    
     inStream.pipe(process.stdout);
    
  3. Web Server in Node js
    Creating a web server in Node.js is relatively straightforward, thanks to Node.js's built-in http module. Here’s a step-by-step guide to create a simple web server,
    i) Using http module

    Create the file named server.js and run it using "node server.js"
    You should see the message Server running athttp://127.0.0.1:3000/ in your terminal.
    Open a web browser and go to http://127.0.0.1:3000/. You should see the message "Hello, World!".

     const http = require('http');
    
     // Define the hostname and port
     const hostname = '127.0.0.1';
     const port = 3000;
    
     // Create the server
     const server = http.createServer((req, res) => {
       res.statusCode = 200;
       res.setHeader('Content-Type', 'text/plain');
       res.end('Hello, World!\n');
     });
    
     // Start the server
     server.listen(port, hostname, () => {
       console.log(`Server running at http://${hostname}:${port}/`);
     });
    

    ii) using Express.js
    Install Express

     npm install express
    

    Update server.js

     const express = require('express');
     const app = express();
     const port = 3000;
    
     app.get('/', (req, res) => {
       res.send('Hello, World!');
     });
    
     app.listen(port, () => {
       console.log(`Server running at http://127.0.0.1:${port}/`);
     });
    

    With Express.js, adding routes and handling different HTTP methods becomes much easier, allowing you to build more complex applications efficiently.

  4. File Operations in Node js
    In Node.js, file system operations such as reading and writing files are handled by the built-in fs module. This module provides both synchronous and asynchronous methods to interact with the file system. Here's an explanation of how to use these methods,
    i) Reading File Asynchronously
    The asynchronous method is preferred as it doesn't block the event loop.

     const fs = require('fs');
    
     fs.readFile('path/to/file.txt', 'utf8', (err, data) => {
         if (err) {
             console.error('Error reading file:', err);
             return;
         }
         console.log('File content:', data);
     });
    

    ii) Reading File Synchronously
    The synchronous method blocks the event loop, which can be problematic for performance in a high-traffic server.

     const fs = require('fs');
    
     try {
         const data = fs.readFileSync('path/to/file.txt', 'utf8');
         console.log('File content:', data);
     } catch (err) {
         console.error('Error reading file:', err);
     }
    

    iii) Writing File Asynchronously
    The asynchronous method is non-blocking.

     const fs = require('fs');
    
     const content = 'This is the content to write into the file';
    
     fs.writeFile('path/to/file.txt', content, 'utf8', (err) => {
         if (err) {
             console.error('Error writing file:', err);
             return;
         }
         console.log('File written successfully');
     });
    

    iv) Writing File Synchronously
    The synchronous method blocks the event loop until the file is written.

     const fs = require('fs');
    
     const content = 'This is the content to write into the file';
    
     try {
         fs.writeFileSync('path/to/file.txt', content, 'utf8');
         console.log('File written successfully');
     } catch (err) {
         console.error('Error writing file:', err);
     }
    

    v) Append to Files Asynchronously

     const fs = require('fs');
    
     const additionalContent = '\nThis is the additional content';
    
     fs.appendFile('path/to/file.txt', additionalContent, 'utf8', (err) => {
         if (err) {
             console.error('Error appending file:', err);
             return;
         }
         console.log('Content appended successfully');
     });
    

    vi) Append to Files Synchronously

     const fs = require('fs');
    
     const additionalContent = '\nThis is the additional content';
    
     try {
         fs.appendFileSync('path/to/file.txt', additionalContent, 'utf8');
         console.log('Content appended successfully');
     } catch (err) {
         console.error('Error appending file:', err);
     }
    

    vii) Deleting Files Asynchronously

     const fs = require('fs');
    
     fs.unlink('path/to/file.txt', (err) => {
         if (err) {
             console.error('Error deleting file:', err);
             return;
         }
         console.log('File deleted successfully');
     });
    

    viii) Deleting Files Synchronously

     const fs = require('fs');
    
     try {
         fs.unlinkSync('path/to/file.txt');
         console.log('File deleted successfully');
     } catch (err) {
         console.error('Error deleting file:', err);
     }
    

    Use asynchronous methods (fs.readFile, fs.writeFile, fs.appendFile, fs.unlink) for non-blocking operations.
    Synchronous methods (fs.readFileSync, fs.writeFileSync, fs.appendFileSync, fs.unlinkSync) are simpler to use but block the event loop and should be avoided in production environments with high concurrency requirements.