Node.js supports multiple module systems: 1) CommonJS (require/exports): Traditional Node.js module system. Example: const fs = require('fs'); module.exports = { ... }. 2) ES Modules (import/export): Modern JavaScript module system. Example: import fs from 'fs'; export const handler = { ... }. 3) ECMAScript Modules in Node.js require either .mjs extension or { 'type': 'module' } in package.json.
Circular dependencies can be handled through: 1) Restructuring code to avoid cycles, 2) Using dependency injection, 3) Moving shared code to a separate module. Example problem: // a.js const b = require('./b'); // b.js const a = require('./a'); Solution: Create shared module: // shared.js module.exports = { sharedFunction() {} }; Then import shared in both modules.
NPM workspaces enable managing multiple packages in a single repository: 1) Define workspaces in root package.json, 2) Share dependencies across packages, 3) Link local packages together. Example: { 'name': 'monorepo', 'workspaces': ['packages/*'], 'private': true }. Directory structure: /packages/pkg1/package.json /packages/pkg2/package.json. Commands work across all workspaces: npm install --workspace=pkg1
Module loading optimization techniques: 1) Use module caching effectively, 2) Implement lazy loading, 3) Bundle modules for production, 4) Use path aliases. Example lazy loading: const getLodash = () => require('lodash'); function processData(data) { const _ = getLodash(); return _.groupBy(data, 'type'); } Cache example: const cache = {}; function requireFromCache(module) { if (!cache[module]) cache[module] = require(module); return cache[module]; }
Node.js module resolution follows these steps: 1) Core modules (like 'fs'), 2) Local modules with relative paths ('./myModule'), 3) node_modules lookup (starts from current directory, moves up), 4) Package.json 'main' field. Example resolution: require('mymodule') → looks in ./node_modules/mymodule → ../node_modules/mymodule → / etc. Resolution can be customized using NODE_PATH environment variable or package.json fields.
Peer dependencies specify packages that must be installed by the consuming application. Used when: 1) Creating plugins/extensions, 2) Avoiding duplicate dependencies, 3) Ensuring compatibility. Example package.json: { 'name': 'my-plugin', 'peerDependencies': { 'react': '>=16.8.0', 'react-dom': '>=16.8.0' } }. The consuming application must install compatible versions of peer dependencies.
Package versioning methods include: 1) Semantic Versioning (MAJOR.MINOR.PATCH), 2) Version ranges (^, ~, *, x), 3) Git URLs, 4) Local paths. Example package.json: { 'dependencies': { 'express': '^4.17.1', // Minor version updates 'lodash': '~4.17.21', // Patch updates only 'mylib': 'file:../mylib', // Local path 'private-pkg': 'git+ssh://git@github.com:org/repo.git' // Git URL } }
Native modules management includes: 1) node-gyp for compilation, 2) Binary distribution using prebuilt packages, 3) Platform-specific installations. Example package.json: { 'dependencies': { 'bcrypt': '^5.0.1' }, 'scripts': { 'install': 'node-gyp rebuild' } } Installation handling: if (process.platform === 'win32') { module.exports = require('./binary/windows'); } else { module.exports = require('./binary/unix'); }