Appearance
模块系统
概述
模块系统是 Eagle2Ae AE 扩展 JavaScript 核心功能的基础组件,提供了完整的 ES6 模块兼容性封装和支持。该系统支持动态模块加载、依赖管理、命名空间隔离等功能。
核心特性
模块化架构
- ES6模块系统 - 使用标准的ES6模块导入导出
- 动态模块加载 - 支持按需加载和懒加载
- 依赖管理 - 自动处理模块依赖关系
- 命名空间隔离 - 防止全局作用域污染
技术实现
javascript
/**
* 模块系统
* 提供ES6模块的兼容性封装和支持
*/
class ModuleSystem {
/**
* 构造函数
*/
constructor() {
// 模块缓存
this.modules = new Map();
// 模块加载队列
this.loadQueue = new Map();
// 模块依赖图
this.dependencyGraph = new Map();
// 模块加载配置
this.config = {
baseUrl: './modules/',
moduleSuffix: '.js',
timeout: 10000, // 10秒超时
maxRetries: 3,
retryDelay: 1000
};
// 事件系统
this.events = new EventEmitter();
// 绑定方法上下文
this.loadModule = this.loadModule.bind(this);
this.defineModule = this.defineModule.bind(this);
this.requireModule = this.requireModule.bind(this);
this.unloadModule = this.unloadModule.bind(this);
console.log('🔧 模块系统已初始化');
}
/**
* 定义模块
* @param {string} moduleName - 模块名称
* @param {Array} dependencies - 依赖模块列表
* @param {Function} factory - 模块工厂函数
* @returns {Promise<Object>} 模块实例
*/
async defineModule(moduleName, dependencies = [], factory) {
try {
console.log(`🔧 定义模块: ${moduleName}`);
// 检查模块是否已存在
if (this.modules.has(moduleName)) {
console.warn(`⚠️ 模块已存在: ${moduleName},将被覆盖`);
}
// 保存依赖关系
this.dependencyGraph.set(moduleName, dependencies);
// 加载依赖模块
const resolvedDependencies = await this.loadDependencies(dependencies);
// 执行工厂函数创建模块
let moduleInstance;
if (typeof factory === 'function') {
moduleInstance = await factory(...resolvedDependencies);
} else {
moduleInstance = factory;
}
// 缓存模块
this.modules.set(moduleName, {
instance: moduleInstance,
dependencies: dependencies,
loadedAt: Date.now(),
exports: {}
});
// 触发模块加载事件
this.events.emit('module:loaded', {
moduleName: moduleName,
dependencies: dependencies,
timestamp: Date.now()
});
console.log(`✅ 模块定义完成: ${moduleName}`);
return moduleInstance;
} catch (error) {
console.error(`❌ 定义模块失败: ${moduleName} - ${error.message}`);
// 触发模块加载错误事件
this.events.emit('module:error', {
moduleName: moduleName,
error: error.message,
timestamp: Date.now()
});
throw error;
}
}
/**
* 加载依赖模块
* @param {Array} dependencies - 依赖模块列表
* @returns {Promise<Array>} 已解析的依赖模块数组
*/
async loadDependencies(dependencies) {
try {
if (!dependencies || dependencies.length === 0) {
return [];
}
const resolvedModules = [];
// 并行加载依赖模块
const loadPromises = dependencies.map(async (dep) => {
try {
const module = await this.loadModule(dep);
return module;
} catch (loadError) {
throw new Error(`加载依赖模块失败: ${dep} - ${loadError.message}`);
}
});
const modules = await Promise.all(loadPromises);
resolvedModules.push(...modules);
return resolvedModules;
} catch (error) {
console.error(`❌ 加载依赖模块失败: ${error.message}`);
throw error;
}
}
/**
* 加载模块
* @param {string} moduleName - 模块名称
* @param {Object} options - 加载选项
* @returns {Promise<Object>} 模块实例
*/
async loadModule(moduleName, options = {}) {
try {
console.log(`📥 加载模块: ${moduleName}`);
// 检查模块是否已在缓存中
if (this.modules.has(moduleName)) {
const cachedModule = this.modules.get(moduleName);
// 检查模块是否过期(如果有缓存策略)
if (!options.forceReload && this.isModuleFresh(cachedModule)) {
console.log(`📋 使用缓存模块: ${moduleName}`);
return cachedModule.instance;
}
}
// 检查是否已在加载队列中
if (this.loadQueue.has(moduleName)) {
console.log(`⏳ 模块已在加载队列中: ${moduleName}`);
return this.loadQueue.get(moduleName);
}
// 创建加载Promise
const loadPromise = this.doLoadModule(moduleName, options);
this.loadQueue.set(moduleName, loadPromise);
try {
const module = await loadPromise;
return module;
} finally {
// 从加载队列中移除
this.loadQueue.delete(moduleName);
}
} catch (error) {
console.error(`❌ 加载模块失败: ${moduleName} - ${error.message}`);
throw error;
}
}
/**
* 实际加载模块逻辑
* @param {string} moduleName - 模块名称
* @param {Object} options - 加载选项
* @returns {Promise<Object>} 模块实例
*/
async doLoadModule(moduleName, options = {}) {
try {
// 构建模块URL
const moduleUrl = this.buildModuleUrl(moduleName);
// 检查是否为内部模块
if (this.isInternalModule(moduleName)) {
return await this.loadInternalModule(moduleName);
}
// 加载外部模块
const moduleCode = await this.fetchModuleCode(moduleUrl, options);
const moduleInstance = await this.evaluateModule(moduleCode, moduleName);
// 缓存模块
this.modules.set(moduleName, {
instance: moduleInstance,
url: moduleUrl,
loadedAt: Date.now(),
version: options.version || '1.0.0'
});
console.log(`✅ 模块加载完成: ${moduleName}`);
return moduleInstance;
} catch (error) {
console.error(`❌ 模块加载失败: ${moduleName} - ${error.message}`);
// 触发错误事件
this.events.emit('module:error', {
moduleName: moduleName,
error: error.message,
timestamp: Date.now()
});
throw error;
}
}
/**
* 构建模块URL
* @param {string} moduleName - 模块名称
* @returns {string} 模块URL
*/
buildModuleUrl(moduleName) {
// 处理相对路径和绝对路径
if (moduleName.startsWith('/') || moduleName.startsWith('./') || moduleName.startsWith('../')) {
return moduleName;
}
// 处理CDN路径
if (moduleName.startsWith('https://') || moduleName.startsWith('http://')) {
return moduleName;
}
// 处理默认模块路径
return `${this.config.baseUrl}${moduleName}${this.config.moduleSuffix}`;
}
/**
* 检查是否为内部模块
* @param {string} moduleName - 模块名称
* @returns {boolean} 是否为内部模块
*/
isInternalModule(moduleName) {
const internalModules = [
'core', 'utils', 'events', 'network', 'storage',
'ui/components', 'ui/styles', 'config', 'logger'
];
return internalModules.some(internal => moduleName.startsWith(internal));
}
/**
* 加载内部模块
* @param {string} moduleName - 模块名称
* @returns {Object} 模块实例
*/
async loadInternalModule(moduleName) {
try {
// 根据模块名称返回对应的内部模块
switch (moduleName) {
case 'core':
return await import('./core/core.js');
case 'utils':
return await import('./utils/utils.js');
case 'events':
return await import('./events/events.js');
case 'network':
return await import('./network/network.js');
case 'storage':
return await import('./storage/storage.js');
case 'ui/components':
return await import('./ui/components/components.js');
case 'ui/styles':
return await import('./ui/styles/styles.js');
case 'config':
return await import('./config/config.js');
case 'logger':
return await import('./logger/logger.js');
default:
throw new Error(`未知的内部模块: ${moduleName}`);
}
} catch (error) {
console.error(`加载内部模块失败: ${moduleName} - ${error.message}`);
throw error;
}
}
/**
* 获取模块代码
* @param {string} url - 模块URL
* @param {Object} options - 选项
* @returns {Promise<string>} 模块代码
*/
async fetchModuleCode(url, options = {}) {
try {
const fetchOptions = {
method: 'GET',
headers: {
'Accept': 'application/javascript',
'Cache-Control': options.cacheControl || 'no-cache'
},
timeout: options.timeout || this.config.timeout
};
// 添加认证头(如果需要)
if (options.authToken) {
fetchOptions.headers['Authorization'] = `Bearer ${options.authToken}`;
}
const response = await fetch(url, fetchOptions);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const moduleCode = await response.text();
// 验证模块代码(简单的语法检查)
if (!this.isValidModuleCode(moduleCode)) {
throw new Error('无效的模块代码');
}
return moduleCode;
} catch (error) {
console.error(`获取模块代码失败: ${url} - ${error.message}`);
// 如果启用了重试,尝试重试
if (options.retryCount < this.config.maxRetries) {
console.log(`🔄 重试加载模块: ${url} (${options.retryCount + 1}/${this.config.maxRetries})`);
await new Promise(resolve => setTimeout(resolve, this.config.retryDelay));
return await this.fetchModuleCode(url, {
...options,
retryCount: (options.retryCount || 0) + 1
});
}
throw error;
}
}
/**
* 验证模块代码
* @param {string} code - 模块代码
* @returns {boolean} 是否有效
*/
isValidModuleCode(code) {
try {
// 简单的语法检查
if (!code || typeof code !== 'string') {
return false;
}
// 检查基本的JavaScript语法特征
const hasExport = code.includes('export') || code.includes('module.exports');
const hasImport = code.includes('import') || code.includes('require');
// 至少应该包含导入或导出语句
return hasExport || hasImport;
} catch (error) {
console.error(`验证模块代码失败: ${error.message}`);
return false;
}
}
/**
* 评估模块代码
* @param {string} code - 模块代码
* @param {string} moduleName - 模块名称
* @returns {Object} 模块实例
*/
async evaluateModule(code, moduleName) {
try {
// 在安全的沙箱环境中执行模块代码
// 注意:在实际生产环境中,应该使用更严格的沙箱机制
// 创建模块上下文
const moduleContext = {
exports: {},
module: {
exports: {}
},
require: this.requireModule.bind(this),
__dirname: this.getModuleDir(moduleName),
__filename: moduleName
};
// 执行模块代码(注意:这是简化的实现,在生产环境中需要更安全的方式)
const moduleFunction = new Function(
'exports', 'module', 'require', '__dirname', '__filename',
`"use strict";\n${code}`
);
moduleFunction(
moduleContext.exports,
moduleContext.module,
moduleContext.require,
moduleContext.__dirname,
moduleContext.__filename
);
// 返回模块导出内容
return moduleContext.module.exports || moduleContext.exports;
} catch (error) {
console.error(`评估模块代码失败: ${moduleName} - ${error.message}`);
throw new Error(`模块代码执行失败: ${error.message}`);
}
}
/**
* 获取模块目录
* @param {string} moduleName - 模块名称
* @returns {string} 模块目录
*/
getModuleDir(moduleName) {
const lastSlashIndex = moduleName.lastIndexOf('/');
if (lastSlashIndex !== -1) {
return moduleName.substring(0, lastSlashIndex);
}
return '.';
}
/**
* 请求模块
* @param {string} moduleName - 模块名称
* @returns {Object} 模块实例
*/
requireModule(moduleName) {
try {
// 检查模块是否已加载
if (this.modules.has(moduleName)) {
return this.modules.get(moduleName).instance;
}
// 检查是否为Node.js内置模块
if (this.isNodeBuiltin(moduleName)) {
return this.getNodeBuiltin(moduleName);
}
// 加载模块
const modulePromise = this.loadModule(moduleName);
// 注意:在实际实现中,这里应该是同步的
// 但由于我们使用了异步加载,这里返回一个Promise包装
return modulePromise;
} catch (error) {
console.error(`请求模块失败: ${moduleName} - ${error.message}`);
throw error;
}
}
/**
* 检查是否为Node.js内置模块
* @param {string} moduleName - 模块名称
* @returns {boolean} 是否为内置模块
*/
isNodeBuiltin(moduleName) {
const builtinModules = [
'fs', 'path', 'util', 'events', 'stream', 'buffer',
'crypto', 'zlib', 'os', 'process', 'console', 'url'
];
return builtinModules.includes(moduleName);
}
/**
* 获取Node.js内置模块
* @param {string} moduleName - 模块名称
* @returns {Object} 内置模块
*/
getNodeBuiltin(moduleName) {
// 在浏览器环境中,这些模块需要polyfill或者模拟实现
switch (moduleName) {
case 'path':
return this.getPathPolyfill();
case 'util':
return this.getUtilPolyfill();
case 'events':
return this.getEventsPolyfill();
default:
console.warn(`⚠️ 不支持的Node.js内置模块: ${moduleName}`);
return {};
}
}
/**
* 获取路径模块polyfill
* @returns {Object} 路径模块
*/
getPathPolyfill() {
return {
join: (...paths) => paths.join('/').replace(/\/+/g, '/'),
resolve: (from, to) => {
const resolved = new URL(to, new URL(from, document.baseURI)).href;
return resolved;
},
dirname: (path) => {
const lastSlashIndex = path.lastIndexOf('/');
return lastSlashIndex === -1 ? '.' : path.substring(0, lastSlashIndex);
},
basename: (path) => {
const lastSlashIndex = path.lastIndexOf('/');
return lastSlashIndex === -1 ? path : path.substring(lastSlashIndex + 1);
},
extname: (path) => {
const lastDotIndex = path.lastIndexOf('.');
return lastDotIndex === -1 ? '' : path.substring(lastDotIndex);
}
};
}
/**
* 获取工具模块polyfill
* @returns {Object} 工具模块
*/
getUtilPolyfill() {
return {
inherits: (ctor, superCtor) => {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
},
format: (format, ...args) => {
let i = 0;
return format.replace(/%s|%d|%j/g, (match) => {
const arg = args[i++];
switch (match) {
case '%s': return String(arg);
case '%d': return Number(arg);
case '%j': return JSON.stringify(arg);
default: return match;
}
});
},
inspect: (obj) => {
return JSON.stringify(obj, null, 2);
}
};
}
/**
* 获取事件模块polyfill
* @returns {Object} 事件模块
*/
getEventsPolyfill() {
return {
EventEmitter: class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
return this;
}
emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(listener => {
listener.apply(this, args);
});
}
return this;
}
removeListener(event, listener) {
if (this.events[event]) {
const index = this.events[event].indexOf(listener);
if (index !== -1) {
this.events[event].splice(index, 1);
}
}
return this;
}
once(event, listener) {
const onceWrapper = (...args) => {
this.removeListener(event, onceWrapper);
listener.apply(this, args);
};
return this.on(event, onceWrapper);
}
}
};
}
/**
* 检查模块是否新鲜(未过期)
* @param {Object} module - 模块对象
* @returns {boolean} 是否新鲜
*/
isModuleFresh(module) {
try {
// 检查模块加载时间(例如:超过1小时认为过期)
const maxAge = 60 * 60 * 1000; // 1小时
const now = Date.now();
return (now - module.loadedAt) < maxAge;
} catch (error) {
console.error(`检查模块新鲜度失败: ${error.message}`);
return true; // 默认认为新鲜
}
}
/**
* 卸载模块
* @param {string} moduleName - 模块名称
* @returns {boolean} 是否卸载成功
*/
unloadModule(moduleName) {
try {
if (!this.modules.has(moduleName)) {
console.warn(`⚠️ 模块不存在: ${moduleName}`);
return false;
}
// 获取模块实例
const module = this.modules.get(moduleName);
// 执行模块清理逻辑(如果模块提供了cleanup方法)
if (module.instance && typeof module.instance.cleanup === 'function') {
try {
module.instance.cleanup();
} catch (cleanupError) {
console.error(`模块清理失败: ${moduleName} - ${cleanupError.message}`);
}
}
// 从缓存中移除模块
this.modules.delete(moduleName);
// 从依赖图中移除
this.dependencyGraph.delete(moduleName);
console.log(`🗑️ 模块已卸载: ${moduleName}`);
// 触发模块卸载事件
this.events.emit('module:unloaded', {
moduleName: moduleName,
timestamp: Date.now()
});
return true;
} catch (error) {
console.error(`❌ 卸载模块失败: ${moduleName} - ${error.message}`);
return false;
}
}
/**
* 获取所有已加载的模块
* @returns {Array} 模块列表
*/
getLoadedModules() {
return Array.from(this.modules.keys()).map(moduleName => ({
name: moduleName,
...this.modules.get(moduleName)
}));
}
/**
* 清理模块系统
*/
cleanup() {
try {
console.log('🧹 清理模块系统...');
// 卸载所有模块
for (const moduleName of Array.from(this.modules.keys())) {
this.unloadModule(moduleName);
}
// 清空加载队列
this.loadQueue.clear();
// 清空依赖图
this.dependencyGraph.clear();
// 清理事件监听器
this.events.removeAllListeners();
console.log('✅ 模块系统清理完成');
} catch (error) {
console.error(`❌ 清理模块系统失败: ${error.message}`);
}
}
}
// 导出模块系统
const moduleSystem = new ModuleSystem();
export default moduleSystem;
// 便利的模块加载函数
export async function load(moduleName, options = {}) {
return await moduleSystem.loadModule(moduleName, options);
}
export async function define(moduleName, dependencies, factory) {
return await moduleSystem.defineModule(moduleName, dependencies, factory);
}
export function unload(moduleName) {
return moduleSystem.unloadModule(moduleName);
}
export function getModules() {
return moduleSystem.getLoadedModules();
}
// 全局模块加载器(兼容AMD/CommonJS)
if (typeof window !== 'undefined') {
window.define = define;
window.require = moduleSystem.requireModule.bind(moduleSystem);
window.loadModule = load;
window.unloadModule = unload;
window.getModules = getModules;
}使用示例
基本使用
javascript
// 1. 加载模块
import { loadModule, defineModule } from './module-system.js';
// 2. 定义模块
const myModule = await defineModule('myModule', ['dependency1', 'dependency2'],
async (dep1, dep2) => {
return {
init: () => console.log('模块已初始化'),
getData: () => '模块数据'
};
}
);
// 3. 使用模块
myModule.init();
console.log(myModule.getData());高级使用
javascript
// 1. 动态加载模块
const dynamicModule = await loadModule('dynamicModule', {
forceReload: true,
timeout: 5000
});
// 2. 模块依赖管理
const moduleWithDeps = await defineModule('moduleWithDeps',
['utils', 'logger', 'config'],
async (utils, logger, config) => {
// 模块实现
return {
process: (data) => {
logger.info('处理数据:', data);
return utils.processData(data, config.settings);
}
};
}
);
// 3. 模块卸载
unloadModule('temporaryModule');最佳实践
模块设计原则
- 单一职责 - 每个模块只负责一个特定功能
- 明确依赖 - 清晰声明模块依赖关系
- 接口封装 - 通过导出接口隐藏内部实现
- 错误处理 - 模块内部处理可能的错误
性能优化
- 合理缓存 - 利用模块缓存避免重复加载
- 按需加载 - 只在需要时加载模块
- 依赖优化 - 减少不必要的依赖
- 代码分割 - 将大模块拆分为小模块
调试技巧
- 启用详细日志 - 在开发环境中启用模块加载日志
- 监控加载性能 - 使用性能监控工具分析模块加载时间
- 依赖分析 - 定期分析模块依赖关系图
- 内存泄漏检测 - 监控模块卸载后的内存使用情况