UNPKG

@error-monitor/sdk

Version:

Monitor SDK - 多平台前端监控SDK解决方案,支持自动环境检测,Web、Taro小程序一站式监控方案

383 lines (328 loc) 10.6 kB
import fs from 'fs'; import path from 'path'; import { execSync } from 'child_process'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const root = path.resolve(__dirname, '..'); /** * 项目自动化配置工具 * 用于快速为新项目配置源码管理和sourcemap生成 */ class ProjectSetupTool { constructor() { this.templates = { webpack: this.getWebpackConfigTemplate(), vite: this.getViteConfigTemplate(), taro: this.getTaroConfigTemplate(), packageJson: this.getPackageJsonTemplate() }; } /** * 获取Webpack配置模板 */ getWebpackConfigTemplate() { return `const path = require('path'); module.exports = { mode: process.env.NODE_ENV || 'development', devtool: 'source-map', output: { path: path.resolve(__dirname, 'dist'), filename: '[name].[contenthash].js', sourceMapFilename: '[name].[contenthash].js.map' }, module: { rules: [ { test: /\.(js|ts|jsx|tsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: [ ['@babel/preset-env', { targets: { browsers: ['last 2 versions'] } }], '@babel/preset-typescript', '@babel/preset-react' ], sourceMaps: true } } } ] } };`; } /** * 获取Vite配置模板 */ getViteConfigTemplate() { return `import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], build: { sourcemap: true, rollupOptions: { output: { manualChunks: { vendor: ['react', 'react-dom'] } } } } });`; } /** * 获取Taro配置模板 */ getTaroConfigTemplate() { return `module.exports = { // Taro 项目配置 mini: { webpackChain(chain) { chain.devtool('source-map'); chain.output.sourceMapFilename('[name].js.map'); } }, h5: { webpackChain(chain) { chain.devtool('source-map'); chain.output.sourceMapFilename('[name].js.map'); } } };`; } /** * 获取package.json脚本模板 */ getPackageJsonTemplate() { return { scripts: { "build:with-sourcemap": "npm run build && npm run pack:source && npm run pack:sourcemap", "pack:source": "./build-with-sourcemap.sh --projectId $npm_package_name --version $npm_package_version --pack-type source", "pack:sourcemap": "./build-with-sourcemap.sh --projectId $npm_package_name --version $npm_package_version --pack-type sourcemap", "upload:source": "npm run pack:source && echo '请将源代码包上传到监控平台源代码管理界面'", "upload:sourcemap": "npm run pack:sourcemap && echo '请将Sourcemap包上传到监控平台Sourcemap管理界面'" }, config: { monitor: { sourceIncludePatterns: ["src/**/*", "config/**/*", "types/**/*", "*.json", "*.js", "*.ts", "*.md"], sourceExcludePatterns: ["node_modules/**", ".git/**", "dist/**", "build/**", "*.log", ".DS_Store"], sourcemapIncludePatterns: ["dist/**/*.map"], sourcemapExcludePatterns: ["dist/**/*.js", "dist/**/*.css", "dist/**/*.html"] } } }; } /** * 检测项目类型 */ detectProjectType(projectPath) { const packageJsonPath = path.join(projectPath, 'package.json'); if (!fs.existsSync(packageJsonPath)) { throw new Error('未找到package.json文件'); } const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); // 检测Taro项目 if (pkg.dependencies && pkg.dependencies['@tarojs/taro']) { return 'taro'; } // 检测Vite项目 if (pkg.devDependencies && pkg.devDependencies.vite) { return 'vite'; } // 检测Webpack项目 if (pkg.devDependencies && pkg.devDependencies.webpack) { return 'webpack'; } // 检测React项目(通过react-scripts) if (pkg.dependencies && pkg.dependencies.react && pkg.dependencies['react-scripts']) { return 'react'; } // 检测Vue项目 if (pkg.dependencies && pkg.dependencies.vue) { return 'vue'; } return 'unknown'; } /** * 配置构建工具 */ setupBuildTool(projectPath, projectType) { const configFileName = this.getConfigFileName(projectType); // 对于未知项目类型,不创建配置文件 if (!configFileName) { console.log('ℹ️ 未知项目类型,跳过构建工具配置'); return false; } const configPath = path.join(projectPath, configFileName); if (fs.existsSync(configPath)) { console.log(`📁 检测到现有配置文件: ${configPath}`); return this.updateExistingConfig(configPath, projectType); } console.log(`📝 创建新的配置文件: ${configPath}`); fs.writeFileSync(configPath, this.templates[projectType]); return true; } /** * 获取配置文件名称 */ getConfigFileName(projectType) { const configMap = { webpack: 'webpack.config.js', vite: 'vite.config.js', taro: 'config/index.js', react: null // React项目使用react-scripts,无需额外配置 }; return configMap[projectType] || null; } /** * 更新现有配置文件 */ updateExistingConfig(configPath, projectType) { const content = fs.readFileSync(configPath, 'utf8'); if (projectType === 'webpack' && !content.includes('source-map')) { const updated = content.replace( /module\.exports\s*=\s*{/, "module.exports = {\n devtool: 'source-map'," ); fs.writeFileSync(configPath, updated); return true; } if (projectType === 'vite' && !content.includes('sourcemap:')) { const updated = content.replace( /build:\s*{/, "build: {\n sourcemap: true," ); fs.writeFileSync(configPath, updated); return true; } console.log('✅ 配置文件已包含sourcemap设置'); return false; } /** * 配置package.json */ setupPackageJson(projectPath) { const packageJsonPath = path.join(projectPath, 'package.json'); const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); const template = this.templates.packageJson; // 合并scripts pkg.scripts = { ...pkg.scripts, ...template.scripts }; // 合并config pkg.config = { ...pkg.config, ...template.config }; fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2)); return true; } /** * 创建监控配置文件 */ createMonitorConfig(projectPath) { const config = { projectId: process.env.PROJECT_ID || 'default-project', version: process.env.VERSION || '1.0.0', includePatterns: [ "src/**/*", "dist/**/*.map", "*.config.*", "package.json", "tsconfig.json", "babel.config.js" ], excludePatterns: [ "node_modules/**", ".git/**", "dist/**/*.js", "dist/**/*.css", "*.log", ".DS_Store" ] }; const configPath = path.join(projectPath, '.monitor-config.json'); fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); return configPath; } /** * 安装监控SDK */ installMonitorSdk(projectPath, projectType) { const packageJsonPath = path.join(projectPath, 'package.json'); const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); // 对于未知项目类型,不安装SDK if (projectType === 'unknown') { console.log('ℹ️ 未知项目类型,跳过SDK安装'); return false; } const sdkPackage = projectType === 'taro' ? '@monitor/taro' : '@monitor/web'; try { console.log(`📦 安装监控SDK: ${sdkPackage}`); // 跳过不存在的包安装 if (!sdkPackage.startsWith('@monitor/')) { console.log(`ℹ️ 跳过不存在的SDK包安装: ${sdkPackage}`); return false; } // 检查包是否存在,如果不存在则跳过 try { execSync(`npm view ${sdkPackage} version`, { stdio: 'ignore' }); } catch { console.log(`ℹ️ SDK包不存在,跳过安装: ${sdkPackage}`); return false; } execSync(`cd ${projectPath} && npm install ${sdkPackage}`, { stdio: 'inherit' }); // 添加到package.json的dependencies pkg.dependencies = pkg.dependencies || {}; pkg.dependencies[sdkPackage] = '^1.0.0'; fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2)); return true; } catch (error) { console.warn('⚠️ SDK安装失败,请手动安装:', error.message); return false; } } /** * 主执行函数 */ async setupProject(projectPath = process.cwd()) { console.log('🚀 开始自动化项目配置...\n'); try { // 1. 检测项目类型 const projectType = this.detectProjectType(projectPath); console.log(`🔍 检测到项目类型: ${projectType}`); // 2. 配置构建工具 console.log('\n🛠️ 配置构建工具...'); this.setupBuildTool(projectPath, projectType); // 3. 配置package.json console.log('\n📄 配置package.json脚本...'); this.setupPackageJson(projectPath); // 4. 创建监控配置文件 console.log('\n⚙️ 创建监控配置文件...'); const configPath = this.createMonitorConfig(projectPath); console.log(`✅ 监控配置文件已创建: ${configPath}`); // 5. 安装监控SDK console.log('\n📦 安装监控SDK...'); this.installMonitorSdk(projectPath, projectType); console.log('\n🎉 项目配置完成!'); console.log('\n📋 下一步操作:'); console.log('1. 运行 npm run build:with-sourcemap 构建并打包源码'); console.log('2. 配置环境变量 PROJECT_ID 和 VERSION'); console.log('3. 运行 npm run upload:source 上传到监控平台'); return true; } catch (error) { console.error('❌ 配置失败:', error.message); return false; } } } // 命令行接口 async function main() { const args = process.argv.slice(2); const projectPath = args[0] || process.cwd(); const setupTool = new ProjectSetupTool(); await setupTool.setupProject(projectPath); } // 导出为模块 if (import.meta.url === `file://${process.argv[1]}`) { main().catch(console.error); } export default ProjectSetupTool;