注意:AI结果仅供参考使用方法1. 环境要求Node.js 16项目目录中包含package.json和源代码2. 安装依赖bashnpm install glob fs-extra babel/parser babel/traverse3. 运行脚本将脚本保存为analyze-migration.js然后在项目根目录执行bashnode analyze-migration.js [项目路径]如果不指定路径默认为当前目录。4. 输出结果会在项目根目录生成migration-report.md报告文件。三、核心代码const fs require(fs-extra); const path require(path); const glob require(glob); const parser require(babel/parser); const traverse require(babel/traverse).default; // 配置 const config { targetDir: process.argv[2] || ., outputFile: path.join(process.argv[2] || ., migration-report.md), }; // 浏览器 API 黑名单 const browserApis [ window, document, localStorage, sessionStorage, location, history, alert, confirm, prompt, fetch, XMLHttpRequest, WebSocket, IntersectionObserver, ResizeObserver, Canvas, Image, FileReader ]; // 第三方库兼容性映射 const libCompat { // UI 库不兼容 element-ui: ❌ 不兼容需替换为 uni-ui 或 uView, ant-design-vue: ❌ 不兼容需替换为 uni-ui 或 uView, vant: ❌ 不兼容需替换为 uni-ui 或 uView, vuetify: ❌ 不兼容, // 图表库需适配 echarts: ⚠️ 有微信小程序版本但绘图逻辑需重写, highcharts: ⚠️ 无官方小程序版需替换, // 工具库兼容 lodash: ✅ 纯 JS 库可保留, dayjs: ✅ 纯 JS 库可保留, moment: ✅ 纯 JS 库可保留, // 其他 axios: ⚠️ 需替换为 uni.request, vue-router: ⚠️ 需替换为 pages.json 配置, vuex: ✅ 可保留持久化需改用 uni.storage, pinia: ✅ 可保留持久化需改用 uni.storage, }; // 1. 读取 package.json function readPackageJson() { const pkgPath path.join(config.targetDir, package.json); if (!fs.existsSync(pkgPath)) { console.error(未找到 package.json); process.exit(1); } return JSON.parse(fs.readFileSync(pkgPath, utf-8)); } // 2. 分析依赖 function analyzeDependencies(pkg) { const deps { ...pkg.dependencies, ...pkg.devDependencies }; const analysis {}; for (const [lib, version] of Object.entries(deps)) { if (libCompat[lib]) { analysis[lib] { version, status: libCompat[lib] }; } else { // 默认未知标记为需人工确认 analysis[lib] { version, status: ❓ 未知需人工确认 }; } } return analysis; } // 3. 扫描源代码检测浏览器 API 和 Vue 特性 function scanSourceCode() { const patterns [**/*.{vue,js,ts}, !node_modules/**, !dist/**]; const files glob.sync(patterns, { cwd: config.targetDir, absolute: true }); let results { browserApiUsage: new Set(), vueFeatures: { customDirective: false, dynamicComponent: false, compositionApi: false, ts: false, renderFunction: false, }, uiLibraries: new Set(), hardwareApiUsage: new Set(), }; for (const file of files) { const content fs.readFileSync(file, utf-8); const ext path.extname(file); // 检测浏览器 API简单正则 for (const api of browserApis) { const regex new RegExp(\\b${api}\\b, g); if (regex.test(content)) { results.browserApiUsage.add(api); } } // 检测 Vue 特性通过 AST 分析更准确这里简单正则 if (content.includes(Vue.directive) || content.includes(app.directive)) { results.vueFeatures.customDirective true; } if (content.includes(component :is) || content.includes(:is)) { results.vueFeatures.dynamicComponent true; } if (content.includes(composition-api) || content.includes(setup() || content.includes(script setup)) { results.vueFeatures.compositionApi true; } if (file.endsWith(.ts) || content.includes(langts)) { results.vueFeatures.ts true; } if (content.includes(render() ext .vue) { results.vueFeatures.renderFunction true; } // 检测 UI 库引用 for (const lib of Object.keys(libCompat)) { if (content.includes(lib)) { results.uiLibraries.add(lib); } } // 检测硬件 API const hardwareKeywords [wx.scanCode, uni.scanCode, getLocation, chooseImage, requestPayment]; for (const kw of hardwareKeywords) { if (content.includes(kw)) { results.hardwareApiUsage.add(kw); } } } return results; } // 4. 检测路由与状态管理 function detectRouterAndStore(pkg, sourceResults) { let router null; if (pkg.dependencies[vue-router]) { router vue-router 已安装; } let store null; if (pkg.dependencies[vuex]) { store vuex 已安装; } else if (pkg.dependencies[pinia]) { store pinia 已安装; } return { router, store }; } // 5. 检测构建工具通过配置文件 function detectBuildTool() { const root config.targetDir; if (fs.existsSync(path.join(root, vite.config.js)) || fs.existsSync(path.join(root, vite.config.ts))) { return Vite; } else if (fs.existsSync(path.join(root, webpack.config.js))) { return Webpack; } else if (fs.existsSync(path.join(root, vue.config.js))) { return Vue CLI (Webpack); } return 未知; } // 6. 静态资源分析简单统计 function analyzeAssets() { const patterns [**/*.{png,jpg,jpeg,gif,svg,ttf,woff,woff2}, !node_modules/**, !dist/**]; const files glob.sync(patterns, { cwd: config.targetDir, absolute: true }); let totalSize 0; let largeFiles []; for (const file of files) { const size fs.statSync(file).size; totalSize size; if (size 100 * 1024) { // 超过 100KB largeFiles.push({ file: path.relative(config.targetDir, file), size }); } } return { totalSize, largeFiles }; } // 7. 生成报告 function generateReport(pkg, depsAnalysis, sourceScan, routerStore, buildTool, assets) { const lines []; lines.push(# H5Vue 项目转微信小程序可行性评估报告\n); lines.push(生成时间${new Date().toLocaleString()}\n); lines.push(项目路径${config.targetDir}\n); // 1. 技术栈概览 lines.push(## 1. 技术栈概览\n); lines.push(- **Vue 版本**${pkg.dependencies[vue] || 未检测到}); lines.push(- **构建工具**${buildTool}); lines.push(- **TypeScript**${sourceScan.vueFeatures.ts ? 是 : 否}); lines.push(- **Composition API**${sourceScan.vueFeatures.compositionApi ? 是 : 否}); lines.push(- **自定义指令**${sourceScan.vueFeatures.customDirective ? 是 : 否}); lines.push(- **动态组件**${sourceScan.vueFeatures.dynamicComponent ? 是 : 否}); lines.push(- **渲染函数**${sourceScan.vueFeatures.renderFunction ? 是 : 否}\n); // 2. 依赖兼容性 lines.push(## 2. 第三方依赖兼容性分析\n); lines.push(| 依赖包 | 版本 | 兼容性评估 |); lines.push(|--------|------|------------|); for (const [lib, info] of Object.entries(depsAnalysis)) { lines.push(| ${lib} | ${info.version} | ${info.status} |); } lines.push(); // 3. 浏览器 API 使用情况 lines.push(## 3. 浏览器 API 使用情况\n); if (sourceScan.browserApiUsage.size 0) { lines.push(以下 API 在小程序中不可用需要替换); for (const api of sourceScan.browserApiUsage) { lines.push(- \${api}\); } } else { lines.push(未检测到明显的浏览器专有 API仅通过正则扫描可能存在漏报。); } lines.push(); // 4. UI 库使用 if (sourceScan.uiLibraries.size 0) { lines.push(## 4. UI 库使用情况\n); lines.push(检测到以下 UI 库均需替换为 uni-app 兼容的组件库); for (const lib of sourceScan.uiLibraries) { lines.push(- ${lib}); } lines.push(); } // 5. 路由与状态管理 lines.push(## 5. 路由与状态管理\n); lines.push(- **路由**${routerStore.router || 未使用 vue-router}); lines.push(- **状态管理**${routerStore.store || 未使用}); if (routerStore.router) { lines.push( - ⚠️ vue-router 需替换为 pages.json 配置路由守卫需重写。); } if (routerStore.store) { lines.push( - ⚠️ 状态管理逻辑可保留但持久化需改用 uni.storage。); } lines.push(); // 6. 硬件能力调用 if (sourceScan.hardwareApiUsage.size 0) { lines.push(## 6. 硬件能力调用\n); lines.push(检测到以下硬件相关 API小程序有对应能力但调用方式不同); for (const api of sourceScan.hardwareApiUsage) { lines.push(- \${api}\); } lines.push(); } // 7. 静态资源 lines.push(## 7. 静态资源分析\n); lines.push(- **总大小**${(assets.totalSize / 1024 / 1024).toFixed(2)} MB); lines.push(- **大文件100KB**${assets.largeFiles.length} 个); if (assets.largeFiles.length 0) { lines.push( 建议将大文件上传至 CDN避免影响小程序包体积。); } lines.push(); // 8. 综合评估与建议 lines.push(## 8. 综合评估与建议\n); let score 100; if (sourceScan.browserApiUsage.size 0) score - 20; if (sourceScan.uiLibraries.size 0) score - 20; if (sourceScan.vueFeatures.dynamicComponent) score - 10; if (routerStore.router) score - 10; if (assets.largeFiles.length 5) score - 10; score Math.max(0, score); lines.push(**兼容性评分**${score}/100分数越高迁移成本越低\n); if (score 80) { lines.push(✅ **建议**项目兼容性较好可考虑使用 uni-app 进行快速迁移预计工作量较小。); } else if (score 50) { lines.push(⚠️ **建议**项目存在中等程度的不兼容项需预留充足时间进行适配。推荐使用跨端框架重构同时保留 H5 版本。); } else { lines.push(❌ **建议**项目兼容性较差直接迁移成本较高。建议评估是否单独开发小程序或仅将部分页面嵌入 WebView。); } lines.push(\n---\n); lines.push(*注本报告基于静态扫描生成可能存在误判或漏报请结合人工审查最终确认。*); return lines.join(\n); } // 主函数 async function main() { const pkg readPackageJson(); const depsAnalysis analyzeDependencies(pkg); const sourceScan scanSourceCode(); const routerStore detectRouterAndStore(pkg, sourceScan); const buildTool detectBuildTool(); const assets analyzeAssets(); const report generateReport(pkg, depsAnalysis, sourceScan, routerStore, buildTool, assets); fs.writeFileSync(config.outputFile, report, utf-8); console.log(报告已生成${config.outputFile}); } main().catch(console.error);
Deepseek工具:H5+Vue 项目转微信小程序报告生成工具
注意:AI结果仅供参考使用方法1. 环境要求Node.js 16项目目录中包含package.json和源代码2. 安装依赖bashnpm install glob fs-extra babel/parser babel/traverse3. 运行脚本将脚本保存为analyze-migration.js然后在项目根目录执行bashnode analyze-migration.js [项目路径]如果不指定路径默认为当前目录。4. 输出结果会在项目根目录生成migration-report.md报告文件。三、核心代码const fs require(fs-extra); const path require(path); const glob require(glob); const parser require(babel/parser); const traverse require(babel/traverse).default; // 配置 const config { targetDir: process.argv[2] || ., outputFile: path.join(process.argv[2] || ., migration-report.md), }; // 浏览器 API 黑名单 const browserApis [ window, document, localStorage, sessionStorage, location, history, alert, confirm, prompt, fetch, XMLHttpRequest, WebSocket, IntersectionObserver, ResizeObserver, Canvas, Image, FileReader ]; // 第三方库兼容性映射 const libCompat { // UI 库不兼容 element-ui: ❌ 不兼容需替换为 uni-ui 或 uView, ant-design-vue: ❌ 不兼容需替换为 uni-ui 或 uView, vant: ❌ 不兼容需替换为 uni-ui 或 uView, vuetify: ❌ 不兼容, // 图表库需适配 echarts: ⚠️ 有微信小程序版本但绘图逻辑需重写, highcharts: ⚠️ 无官方小程序版需替换, // 工具库兼容 lodash: ✅ 纯 JS 库可保留, dayjs: ✅ 纯 JS 库可保留, moment: ✅ 纯 JS 库可保留, // 其他 axios: ⚠️ 需替换为 uni.request, vue-router: ⚠️ 需替换为 pages.json 配置, vuex: ✅ 可保留持久化需改用 uni.storage, pinia: ✅ 可保留持久化需改用 uni.storage, }; // 1. 读取 package.json function readPackageJson() { const pkgPath path.join(config.targetDir, package.json); if (!fs.existsSync(pkgPath)) { console.error(未找到 package.json); process.exit(1); } return JSON.parse(fs.readFileSync(pkgPath, utf-8)); } // 2. 分析依赖 function analyzeDependencies(pkg) { const deps { ...pkg.dependencies, ...pkg.devDependencies }; const analysis {}; for (const [lib, version] of Object.entries(deps)) { if (libCompat[lib]) { analysis[lib] { version, status: libCompat[lib] }; } else { // 默认未知标记为需人工确认 analysis[lib] { version, status: ❓ 未知需人工确认 }; } } return analysis; } // 3. 扫描源代码检测浏览器 API 和 Vue 特性 function scanSourceCode() { const patterns [**/*.{vue,js,ts}, !node_modules/**, !dist/**]; const files glob.sync(patterns, { cwd: config.targetDir, absolute: true }); let results { browserApiUsage: new Set(), vueFeatures: { customDirective: false, dynamicComponent: false, compositionApi: false, ts: false, renderFunction: false, }, uiLibraries: new Set(), hardwareApiUsage: new Set(), }; for (const file of files) { const content fs.readFileSync(file, utf-8); const ext path.extname(file); // 检测浏览器 API简单正则 for (const api of browserApis) { const regex new RegExp(\\b${api}\\b, g); if (regex.test(content)) { results.browserApiUsage.add(api); } } // 检测 Vue 特性通过 AST 分析更准确这里简单正则 if (content.includes(Vue.directive) || content.includes(app.directive)) { results.vueFeatures.customDirective true; } if (content.includes(component :is) || content.includes(:is)) { results.vueFeatures.dynamicComponent true; } if (content.includes(composition-api) || content.includes(setup() || content.includes(script setup)) { results.vueFeatures.compositionApi true; } if (file.endsWith(.ts) || content.includes(langts)) { results.vueFeatures.ts true; } if (content.includes(render() ext .vue) { results.vueFeatures.renderFunction true; } // 检测 UI 库引用 for (const lib of Object.keys(libCompat)) { if (content.includes(lib)) { results.uiLibraries.add(lib); } } // 检测硬件 API const hardwareKeywords [wx.scanCode, uni.scanCode, getLocation, chooseImage, requestPayment]; for (const kw of hardwareKeywords) { if (content.includes(kw)) { results.hardwareApiUsage.add(kw); } } } return results; } // 4. 检测路由与状态管理 function detectRouterAndStore(pkg, sourceResults) { let router null; if (pkg.dependencies[vue-router]) { router vue-router 已安装; } let store null; if (pkg.dependencies[vuex]) { store vuex 已安装; } else if (pkg.dependencies[pinia]) { store pinia 已安装; } return { router, store }; } // 5. 检测构建工具通过配置文件 function detectBuildTool() { const root config.targetDir; if (fs.existsSync(path.join(root, vite.config.js)) || fs.existsSync(path.join(root, vite.config.ts))) { return Vite; } else if (fs.existsSync(path.join(root, webpack.config.js))) { return Webpack; } else if (fs.existsSync(path.join(root, vue.config.js))) { return Vue CLI (Webpack); } return 未知; } // 6. 静态资源分析简单统计 function analyzeAssets() { const patterns [**/*.{png,jpg,jpeg,gif,svg,ttf,woff,woff2}, !node_modules/**, !dist/**]; const files glob.sync(patterns, { cwd: config.targetDir, absolute: true }); let totalSize 0; let largeFiles []; for (const file of files) { const size fs.statSync(file).size; totalSize size; if (size 100 * 1024) { // 超过 100KB largeFiles.push({ file: path.relative(config.targetDir, file), size }); } } return { totalSize, largeFiles }; } // 7. 生成报告 function generateReport(pkg, depsAnalysis, sourceScan, routerStore, buildTool, assets) { const lines []; lines.push(# H5Vue 项目转微信小程序可行性评估报告\n); lines.push(生成时间${new Date().toLocaleString()}\n); lines.push(项目路径${config.targetDir}\n); // 1. 技术栈概览 lines.push(## 1. 技术栈概览\n); lines.push(- **Vue 版本**${pkg.dependencies[vue] || 未检测到}); lines.push(- **构建工具**${buildTool}); lines.push(- **TypeScript**${sourceScan.vueFeatures.ts ? 是 : 否}); lines.push(- **Composition API**${sourceScan.vueFeatures.compositionApi ? 是 : 否}); lines.push(- **自定义指令**${sourceScan.vueFeatures.customDirective ? 是 : 否}); lines.push(- **动态组件**${sourceScan.vueFeatures.dynamicComponent ? 是 : 否}); lines.push(- **渲染函数**${sourceScan.vueFeatures.renderFunction ? 是 : 否}\n); // 2. 依赖兼容性 lines.push(## 2. 第三方依赖兼容性分析\n); lines.push(| 依赖包 | 版本 | 兼容性评估 |); lines.push(|--------|------|------------|); for (const [lib, info] of Object.entries(depsAnalysis)) { lines.push(| ${lib} | ${info.version} | ${info.status} |); } lines.push(); // 3. 浏览器 API 使用情况 lines.push(## 3. 浏览器 API 使用情况\n); if (sourceScan.browserApiUsage.size 0) { lines.push(以下 API 在小程序中不可用需要替换); for (const api of sourceScan.browserApiUsage) { lines.push(- \${api}\); } } else { lines.push(未检测到明显的浏览器专有 API仅通过正则扫描可能存在漏报。); } lines.push(); // 4. UI 库使用 if (sourceScan.uiLibraries.size 0) { lines.push(## 4. UI 库使用情况\n); lines.push(检测到以下 UI 库均需替换为 uni-app 兼容的组件库); for (const lib of sourceScan.uiLibraries) { lines.push(- ${lib}); } lines.push(); } // 5. 路由与状态管理 lines.push(## 5. 路由与状态管理\n); lines.push(- **路由**${routerStore.router || 未使用 vue-router}); lines.push(- **状态管理**${routerStore.store || 未使用}); if (routerStore.router) { lines.push( - ⚠️ vue-router 需替换为 pages.json 配置路由守卫需重写。); } if (routerStore.store) { lines.push( - ⚠️ 状态管理逻辑可保留但持久化需改用 uni.storage。); } lines.push(); // 6. 硬件能力调用 if (sourceScan.hardwareApiUsage.size 0) { lines.push(## 6. 硬件能力调用\n); lines.push(检测到以下硬件相关 API小程序有对应能力但调用方式不同); for (const api of sourceScan.hardwareApiUsage) { lines.push(- \${api}\); } lines.push(); } // 7. 静态资源 lines.push(## 7. 静态资源分析\n); lines.push(- **总大小**${(assets.totalSize / 1024 / 1024).toFixed(2)} MB); lines.push(- **大文件100KB**${assets.largeFiles.length} 个); if (assets.largeFiles.length 0) { lines.push( 建议将大文件上传至 CDN避免影响小程序包体积。); } lines.push(); // 8. 综合评估与建议 lines.push(## 8. 综合评估与建议\n); let score 100; if (sourceScan.browserApiUsage.size 0) score - 20; if (sourceScan.uiLibraries.size 0) score - 20; if (sourceScan.vueFeatures.dynamicComponent) score - 10; if (routerStore.router) score - 10; if (assets.largeFiles.length 5) score - 10; score Math.max(0, score); lines.push(**兼容性评分**${score}/100分数越高迁移成本越低\n); if (score 80) { lines.push(✅ **建议**项目兼容性较好可考虑使用 uni-app 进行快速迁移预计工作量较小。); } else if (score 50) { lines.push(⚠️ **建议**项目存在中等程度的不兼容项需预留充足时间进行适配。推荐使用跨端框架重构同时保留 H5 版本。); } else { lines.push(❌ **建议**项目兼容性较差直接迁移成本较高。建议评估是否单独开发小程序或仅将部分页面嵌入 WebView。); } lines.push(\n---\n); lines.push(*注本报告基于静态扫描生成可能存在误判或漏报请结合人工审查最终确认。*); return lines.join(\n); } // 主函数 async function main() { const pkg readPackageJson(); const depsAnalysis analyzeDependencies(pkg); const sourceScan scanSourceCode(); const routerStore detectRouterAndStore(pkg, sourceScan); const buildTool detectBuildTool(); const assets analyzeAssets(); const report generateReport(pkg, depsAnalysis, sourceScan, routerStore, buildTool, assets); fs.writeFileSync(config.outputFile, report, utf-8); console.log(报告已生成${config.outputFile}); } main().catch(console.error);