Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

require与module.exports

本章深入探讨CommonJS模块系统的两个核心机制:require()函数和module.exports对象。理解它们的工作原理和最佳实践对于编写高质量的Node.js代码至关重要。

require()函数深入解析

require()的工作流程

// require()的内部工作流程示例

// 1. 路径解析
const resolvedPath = require.resolve('./my-module');

// 2. 检查缓存
if (require.cache[resolvedPath]) {
    return require.cache[resolvedPath].exports;
}

// 3. 创建新模块对象
const module = {
    id: resolvedPath,
    filename: resolvedPath,
    loaded: false,
    parent: currentModule,
    children: [],
    exports: {}
};

// 4. 加载并执行模块
const moduleWrapper = NativeModule.wrap(moduleContent);
const compiledWrapper = vm.runInThisContext(moduleWrapper);
compiledWrapper.call(module.exports, module.exports, require, module, __filename, __dirname);

// 5. 标记模块已加载
module.loaded = true;

// 6. 缓存模块
require.cache[resolvedPath] = module;

// 7. 返回exports
return module.exports;

require()的不同用法

// require-usage.js

// 1. 基本用法
const fs = require('fs');
const path = require('path');
const myModule = require('./my-module');

// 2. 条件require
let config;
if (process.env.NODE_ENV === 'production') {
    config = require('./config/production.json');
} else {
    config = require('./config/development.json');
}

// 3. 动态require
function loadModule(moduleName) {
    try {
        return require(moduleName);
    } catch (error) {
        console.log(`Module ${moduleName} not found`);
        return null;
    }
}

// 4. require表达式计算
const moduleName = './modules/' + process.argv[2];
const dynamicModule = require(moduleName);

// 5. 解构require
const { readFile, writeFile } = require('fs/promises');
const { join, dirname } = require('path');

// 6. require JSON文件
const packageInfo = require('./package.json');
const config = require('./config.json');

// 7. require.resolve - 仅解析路径不加载
const modulePath = require.resolve('lodash');
console.log('Lodash path:', modulePath);

// 8. 检查模块是否存在
function moduleExists(name) {
    try {
        require.resolve(name);
        return true;
    } catch (e) {
        return false;
    }
}

require缓存机制

// require-cache.js

// 演示模块缓存
console.log('=== 模块缓存演示 ===');

// 第一次require - 执行模块代码
console.log('First require:');
const module1 = require('./counter-module');
console.log('Counter value:', module1.getValue()); // 0

// 增加计数
module1.increment();
module1.increment();
console.log('After increment:', module1.getValue()); // 2

// 第二次require - 返回缓存
console.log('Second require:');
const module2 = require('./counter-module');
console.log('Counter value:', module2.getValue()); // 2 (不是0!)

// 验证是同一个对象
console.log('Same object?', module1 === module2); // true

// counter-module.js
console.log('Counter module executing...');

let counter = 0;

module.exports = {
    increment() {
        counter++;
    },
    getValue() {
        return counter;
    }
};

// 缓存操作
console.log('\n=== 缓存操作 ===');

// 查看缓存的模块
console.log('Cached modules:');
Object.keys(require.cache).forEach(key => {
    console.log(key);
});

// 删除缓存并重新加载
const modulePath = require.resolve('./counter-module');
delete require.cache[modulePath];

console.log('After clearing cache:');
const module3 = require('./counter-module');
console.log('Counter value:', module3.getValue()); // 0 (重新执行了模块)

require()的错误处理

// require-error-handling.js

// 基本错误处理
function safeRequire(modulePath, defaultValue = null) {
    try {
        return require(modulePath);
    } catch (error) {
        console.log(`Failed to require ${modulePath}:`, error.message);
        return defaultValue;
    }
}

// 区分不同类型的错误
function detailedRequire(modulePath) {
    try {
        return require(modulePath);
    } catch (error) {
        switch (error.code) {
            case 'MODULE_NOT_FOUND':
                console.log(`Module not found: ${modulePath}`);
                break;
            case 'ENOENT':
                console.log(`File not found: ${modulePath}`);
                break;
            default:
                console.log(`Error loading module: ${error.message}`);
                throw error; // 重新抛出未知错误
        }
        return null;
    }
}

// 可选依赖加载
function loadOptionalDependencies(dependencies) {
    const loaded = {};
    
    dependencies.forEach(dep => {
        try {
            loaded[dep] = require(dep);
            console.log(`✅ Loaded: ${dep}`);
        } catch (error) {
            console.log(`⚠️  Optional dependency not found: ${dep}`);
            loaded[dep] = null;
        }
    });
    
    return loaded;
}

// 使用示例
const optionalDeps = loadOptionalDependencies([
    'colors',
    'moment',
    'non-existent-package'
]);

// 带重试的require
function requireWithRetry(modulePath, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            return require(modulePath);
        } catch (error) {
            if (i === maxRetries - 1) {
                throw error;
            }
            console.log(`Retry ${i + 1} for ${modulePath}`);
        }
    }
}

module.exports详解

module.exports vs exports

// exports-comparison.js

// 理解module.exports和exports的关系
console.log('初始状态:');
console.log('exports === module.exports:', exports === module.exports); // true

// exports是module.exports的引用
exports.method1 = function() {
    return 'method1 from exports';
};

module.exports.method2 = function() {
    return 'method2 from module.exports';
};

console.log('添加方法后:');
console.log('exports === module.exports:', exports === module.exports); // 仍然是true

// 危险操作:重新赋值exports
exports = {
    method3: function() {
        return 'method3';
    }
};

console.log('重新赋值exports后:');
console.log('exports === module.exports:', exports === module.exports); // false!

// 此时module.exports仍然包含method1和method2
// 但exports指向了新对象,包含method3

// 正确的重新赋值方式
module.exports = {
    method4: function() {
        return 'method4';
    }
};

// 现在module.exports只包含method4了

不同的导出模式

// export-patterns.js

// 1. 对象导出模式
module.exports = {
    name: 'MyModule',
    version: '1.0.0',
    
    init() {
        console.log(`${this.name} v${this.version} initialized`);
    },
    
    process(data) {
        return data.toUpperCase();
    }
};

// 2. 类导出模式
class Calculator {
    add(a, b) { return a + b; }
    subtract(a, b) { return a - b; }
    multiply(a, b) { return a * b; }
    divide(a, b) { 
        if (b === 0) throw new Error('Division by zero');
        return a / b; 
    }
}

module.exports = Calculator;

// 3. 函数导出模式
function createLogger(level = 'info') {
    const levels = ['debug', 'info', 'warn', 'error'];
    const currentLevel = levels.indexOf(level);
    
    return {
        log(message, msgLevel = 'info') {
            const msgIndex = levels.indexOf(msgLevel);
            if (msgIndex >= currentLevel) {
                console.log(`[${msgLevel.toUpperCase()}] ${message}`);
            }
        }
    };
}

module.exports = createLogger;

// 4. 混合导出模式
function mainFunction() {
    return 'Main functionality';
}

// 将函数本身作为默认导出
module.exports = mainFunction;

// 添加额外的属性和方法
module.exports.helper = function() {
    return 'Helper functionality';
};

module.exports.constant = 42;

module.exports.SubClass = class {
    constructor() {
        this.name = 'SubClass';
    }
};

// 5. 条件导出模式
if (process.env.NODE_ENV === 'development') {
    module.exports = {
        log: console.log,
        warn: console.warn,
        error: console.error,
        debug: console.debug
    };
} else {
    module.exports = {
        log() {}, // 生产环境静默
        warn: console.warn,
        error: console.error,
        debug() {}
    };
}

渐进式导出

// progressive-exports.js

// 可以逐步构建exports对象

// 先创建基础结构
module.exports = {};

// 添加常量
module.exports.VERSION = '2.1.0';
module.exports.DEFAULT_CONFIG = {
    timeout: 5000,
    retries: 3
};

// 添加工具函数
module.exports.utils = {};

module.exports.utils.formatDate = function(date) {
    return date.toISOString().split('T')[0];
};

module.exports.utils.generateId = function() {
    return Math.random().toString(36).substr(2, 9);
};

// 添加主要功能
module.exports.createClient = function(config = {}) {
    const finalConfig = { ...module.exports.DEFAULT_CONFIG, ...config };
    
    return {
        config: finalConfig,
        
        async request(url) {
            console.log(`Requesting ${url} with timeout ${finalConfig.timeout}ms`);
            // 模拟请求
            return { status: 200, data: 'response data' };
        }
    };
};

// 添加错误类
class ClientError extends Error {
    constructor(message, code) {
        super(message);
        this.name = 'ClientError';
        this.code = code;
    }
}

module.exports.ClientError = ClientError;

// 添加验证函数
module.exports.validate = {
    url(url) {
        try {
            new URL(url);
            return true;
        } catch {
            return false;
        }
    },
    
    config(config) {
        if (typeof config !== 'object') return false;
        if (config.timeout && typeof config.timeout !== 'number') return false;
        if (config.retries && typeof config.retries !== 'number') return false;
        return true;
    }
};

高级模式和技巧

1. 模块工厂模式

// module-factory.js

// 工厂函数创建配置化的模块
function createDatabase(options = {}) {
    const {
        host = 'localhost',
        port = 5432,
        database = 'myapp',
        pool = { min: 2, max: 10 }
    } = options;
    
    let connection = null;
    
    return {
        async connect() {
            if (!connection) {
                console.log(`Connecting to ${host}:${port}/${database}`);
                connection = { 
                    host, 
                    port, 
                    database, 
                    connected: true 
                };
            }
            return connection;
        },
        
        async query(sql, params = []) {
            const conn = await this.connect();
            console.log(`Executing: ${sql}`, params);
            return { rows: [], rowCount: 0 };
        },
        
        async close() {
            if (connection) {
                console.log('Closing database connection');
                connection.connected = false;
                connection = null;
            }
        },
        
        getConfig() {
            return { host, port, database, pool };
        }
    };
}

module.exports = createDatabase;

// 使用工厂模式
// const db = require('./database-factory')({
//     host: 'prod-server',
//     port: 5432,
//     database: 'production_db'
// });

2. 单例模式

// singleton-pattern.js

// 单例配置管理器
let instance = null;

class ConfigManager {
    constructor() {
        if (instance) {
            return instance;
        }
        
        this.config = {};
        this.loaded = false;
        instance = this;
    }
    
    load(configPath) {
        if (!this.loaded) {
            try {
                this.config = require(configPath);
                this.loaded = true;
                console.log('Configuration loaded');
            } catch (error) {
                console.error('Failed to load configuration:', error);
                this.config = {};
            }
        }
        return this;
    }
    
    get(key, defaultValue = null) {
        return this.getNestedValue(this.config, key, defaultValue);
    }
    
    set(key, value) {
        this.setNestedValue(this.config, key, value);
    }
    
    getNestedValue(obj, path, defaultValue) {
        const keys = path.split('.');
        let current = obj;
        
        for (const key of keys) {
            if (current === null || current === undefined || !(key in current)) {
                return defaultValue;
            }
            current = current[key];
        }
        
        return current;
    }
    
    setNestedValue(obj, path, value) {
        const keys = path.split('.');
        const lastKey = keys.pop();
        let current = obj;
        
        for (const key of keys) {
            if (!(key in current)) {
                current[key] = {};
            }
            current = current[key];
        }
        
        current[lastKey] = value;
    }
}

// 导出单例实例
module.exports = new ConfigManager();

// 无论在哪里require,都是同一个实例
// const config1 = require('./config-manager');
// const config2 = require('./config-manager');
// console.log(config1 === config2); // true

3. 插件系统

// plugin-system.js

class PluginManager {
    constructor() {
        this.plugins = new Map();
        this.hooks = new Map();
    }
    
    register(name, plugin) {
        if (typeof plugin !== 'object') {
            throw new Error('Plugin must be an object');
        }
        
        if (typeof plugin.init !== 'function') {
            throw new Error('Plugin must have an init method');
        }
        
        this.plugins.set(name, plugin);
        console.log(`Plugin registered: ${name}`);
        
        // 初始化插件
        plugin.init(this);
        
        // 注册插件的钩子
        if (plugin.hooks) {
            Object.entries(plugin.hooks).forEach(([hookName, handler]) => {
                this.addHook(hookName, handler);
            });
        }
    }
    
    addHook(name, handler) {
        if (!this.hooks.has(name)) {
            this.hooks.set(name, []);
        }
        this.hooks.get(name).push(handler);
    }
    
    async executeHook(name, ...args) {
        const handlers = this.hooks.get(name) || [];
        const results = [];
        
        for (const handler of handlers) {
            try {
                const result = await handler(...args);
                results.push(result);
            } catch (error) {
                console.error(`Hook ${name} error:`, error);
            }
        }
        
        return results;
    }
    
    getPlugin(name) {
        return this.plugins.get(name);
    }
    
    unregister(name) {
        const plugin = this.plugins.get(name);
        if (plugin && typeof plugin.destroy === 'function') {
            plugin.destroy();
        }
        this.plugins.delete(name);
        console.log(`Plugin unregistered: ${name}`);
    }
}

// 导出插件管理器
const pluginManager = new PluginManager();

// 提供便捷的插件加载函数
function loadPlugin(pluginPath) {
    try {
        const plugin = require(pluginPath);
        const name = plugin.name || require('path').basename(pluginPath);
        pluginManager.register(name, plugin);
        return plugin;
    } catch (error) {
        console.error(`Failed to load plugin ${pluginPath}:`, error);
        return null;
    }
}

module.exports = {
    pluginManager,
    loadPlugin
};

4. 延迟初始化

// lazy-initialization.js

// 延迟初始化的数据库连接
let _connection = null;
let _connecting = false;
let _connectionPromise = null;

async function getConnection() {
    if (_connection) {
        return _connection;
    }
    
    if (_connecting) {
        return _connectionPromise;
    }
    
    _connecting = true;
    _connectionPromise = initializeConnection();
    
    try {
        _connection = await _connectionPromise;
        return _connection;
    } finally {
        _connecting = false;
        _connectionPromise = null;
    }
}

async function initializeConnection() {
    console.log('Initializing database connection...');
    
    // 模拟异步连接过程
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    const connection = {
        id: Math.random().toString(36),
        connected: true,
        
        async query(sql) {
            if (!this.connected) {
                throw new Error('Connection closed');
            }
            console.log(`Executing: ${sql}`);
            return { rows: [], count: 0 };
        },
        
        async close() {
            this.connected = false;
            _connection = null;
            console.log('Connection closed');
        }
    };
    
    console.log('Database connection established');
    return connection;
}

// 导出接口
module.exports = {
    async query(sql) {
        const conn = await getConnection();
        return conn.query(sql);
    },
    
    async close() {
        if (_connection) {
            await _connection.close();
        }
    },
    
    isConnected() {
        return _connection && _connection.connected;
    }
};

性能优化技巧

1. 条件require

// conditional-require.js

// 避免不必要的require
let heavyModule = null;

function getHeavyModule() {
    if (!heavyModule) {
        console.log('Loading heavy module...');
        heavyModule = require('./heavy-computation');
    }
    return heavyModule;
}

// 只有在需要时才加载
function performHeavyOperation(data) {
    const heavy = getHeavyModule();
    return heavy.process(data);
}

// 基于功能检测的条件require
let cryptoModule = null;

function getCrypto() {
    if (!cryptoModule) {
        try {
            cryptoModule = require('crypto');
        } catch (error) {
            // 回退到其他实现
            cryptoModule = require('./crypto-fallback');
        }
    }
    return cryptoModule;
}

// 基于环境的条件require
const debugMode = process.env.NODE_ENV === 'development';

let debugUtils = null;
if (debugMode) {
    debugUtils = require('./debug-utils');
}

function debug(message) {
    if (debugMode && debugUtils) {
        debugUtils.log(message);
    }
}

module.exports = {
    performHeavyOperation,
    getCrypto,
    debug
};

2. require缓存优化

// cache-optimization.js

// 手动管理require缓存
class RequireCache {
    static clear(modulePath) {
        const resolvedPath = require.resolve(modulePath);
        delete require.cache[resolvedPath];
    }
    
    static clearPattern(pattern) {
        const regex = new RegExp(pattern);
        Object.keys(require.cache).forEach(key => {
            if (regex.test(key)) {
                delete require.cache[key];
            }
        });
    }
    
    static preload(modules) {
        modules.forEach(modulePath => {
            try {
                require(modulePath);
                console.log(`Preloaded: ${modulePath}`);
            } catch (error) {
                console.warn(`Failed to preload: ${modulePath}`);
            }
        });
    }
    
    static getStats() {
        const cached = Object.keys(require.cache);
        return {
            count: cached.length,
            modules: cached.map(path => ({
                path,
                loaded: require.cache[path].loaded
            }))
        };
    }
}

// 智能require封装
function smartRequire(modulePath, options = {}) {
    const { cache = true, reload = false } = options;
    
    if (reload) {
        RequireCache.clear(modulePath);
    }
    
    const module = require(modulePath);
    
    if (!cache) {
        // 立即清除缓存
        setImmediate(() => {
            RequireCache.clear(modulePath);
        });
    }
    
    return module;
}

module.exports = {
    RequireCache,
    smartRequire
};

调试和监控

1. require跟踪

// require-tracer.js

// 跟踪require调用
const originalRequire = module.constructor.prototype.require;

module.constructor.prototype.require = function(id) {
    const start = Date.now();
    console.log(`📦 Requiring: ${id}`);
    
    try {
        const result = originalRequire.call(this, id);
        const duration = Date.now() - start;
        console.log(`✅ Loaded: ${id} (${duration}ms)`);
        return result;
    } catch (error) {
        const duration = Date.now() - start;
        console.log(`❌ Failed: ${id} (${duration}ms) - ${error.message}`);
        throw error;
    }
};

// 使用示例
const fs = require('fs');        // 📦 Requiring: fs / ✅ Loaded: fs (1ms)
const path = require('path');    // 📦 Requiring: path / ✅ Loaded: path (0ms)

// 恢复原始require
function restoreRequire() {
    module.constructor.prototype.require = originalRequire;
}

module.exports = { restoreRequire };

2. 模块依赖分析

// dependency-analyzer.js

class DependencyAnalyzer {
    constructor() {
        this.dependencies = new Map();
        this.loadTimes = new Map();
    }
    
    analyze() {
        Object.entries(require.cache).forEach(([path, moduleObj]) => {
            const deps = moduleObj.children.map(child => child.filename);
            this.dependencies.set(path, deps);
        });
        
        return this.generateReport();
    }
    
    generateReport() {
        const report = {
            totalModules: this.dependencies.size,
            dependencies: {},
            circularDependencies: this.findCircularDependencies(),
            heaviestModules: this.findHeaviestModules()
        };
        
        this.dependencies.forEach((deps, module) => {
            report.dependencies[module] = {
                dependsOn: deps,
                dependentCount: deps.length
            };
        });
        
        return report;
    }
    
    findCircularDependencies() {
        // 简化的循环依赖检测
        const visited = new Set();
        const visiting = new Set();
        const cycles = [];
        
        const dfs = (module, path = []) => {
            if (visiting.has(module)) {
                const cycleStart = path.indexOf(module);
                cycles.push(path.slice(cycleStart).concat(module));
                return;
            }
            
            if (visited.has(module)) return;
            
            visiting.add(module);
            path.push(module);
            
            const deps = this.dependencies.get(module) || [];
            deps.forEach(dep => dfs(dep, [...path]));
            
            visiting.delete(module);
            visited.add(module);
        };
        
        this.dependencies.forEach((_, module) => {
            if (!visited.has(module)) {
                dfs(module);
            }
        });
        
        return cycles;
    }
    
    findHeaviestModules(top = 10) {
        const modules = Array.from(this.dependencies.entries())
            .map(([module, deps]) => ({
                module,
                dependencyCount: deps.length
            }))
            .sort((a, b) => b.dependencyCount - a.dependencyCount)
            .slice(0, top);
        
        return modules;
    }
}

module.exports = DependencyAnalyzer;

总结

require()module.exports是CommonJS模块系统的核心:

  • require(): 同步加载、缓存机制、路径解析
  • module.exports: 灵活的导出方式、与exports的关系
  • 高级模式: 工厂模式、单例模式、插件系统
  • 性能优化: 条件加载、缓存管理、延迟初始化
  • 调试工具: 依赖跟踪、性能监控、循环依赖检测

理解这些机制有助于编写更高效、更可维护的Node.js应用。


下一章: 模块缓存机制