| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- #!/usr/bin/env node
- /**
- * Node.js 依赖:按需执行 npm install,并同步 dependencies.txt
- * 用法:node nodejs-dependencies-install.js [--update]
- * 无参数:若无 node_modules 或缺少依赖则 npm install,否则跳过
- * --update:仅对比 node_modules 与 dependencies.txt,不一致时更新 dependencies.txt
- */
- const fs = require('fs');
- const path = require('path');
- const { execSync } = require('child_process');
- const scriptDir = __dirname;
- const projectRoot = path.resolve(scriptDir, '..', '..', '..');
- const config = require(path.join(projectRoot, 'configs', 'config.js'));
- const nodeDir = config.nodeDir || path.dirname(config.nodejsPath);
- const nodeModulesPath = path.join(nodeDir, 'node_modules');
- const dependenciesFile = path.join(scriptDir, 'dependencies.txt');
- const nodeExe = path.join(nodeDir, process.platform === 'win32' ? 'node.exe' : 'node');
- const npmCmd = config.npmCmdPath || path.join(nodeDir, process.platform === 'win32' ? 'npm.cmd' : 'npm');
- if (!fs.existsSync(nodeDir)) {
- console.error('[X] nodejs/node not found.');
- process.exit(1);
- }
- if (!fs.existsSync(nodeModulesPath)) {
- fs.mkdirSync(nodeModulesPath, { recursive: true });
- }
- process.env.PATH = nodeDir + path.delimiter + (process.env.PATH || '');
- const colors = { reset: '\x1b[0m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', cyan: '\x1b[36m' };
- function log(message, color = 'reset') {
- console.log(`${colors[color]}${message}${colors.reset}`);
- }
- function getRequiredPackages() {
- const pkgPath = path.join(projectRoot, 'package.json');
- if (!fs.existsSync(pkgPath)) return [];
- try {
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
- const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
- return Object.keys(deps);
- } catch (_) { return []; }
- }
- function isPackageInstalled(name) {
- if (name.startsWith('@')) {
- const parts = name.slice(1).split('/');
- const pkgPath = path.join(nodeModulesPath, '@' + parts[0], parts[1] || '');
- return fs.existsSync(path.join(pkgPath, 'package.json'));
- }
- return fs.existsSync(path.join(nodeModulesPath, name, 'package.json'));
- }
- function needsInstall() {
- const installed = getInstalledPackages();
- const installedCount = Object.keys(installed).length;
- const required = getRequiredPackages();
- if (required.length === 0) return true;
- if (installedCount === 0) return true;
- for (const name of required) {
- if (!isPackageInstalled(name)) return true;
- }
- try {
- execSync(`"${npmCmd}" ls --prefix ${path.join(nodeDir).replace(/\\/g, '/')}`, {
- stdio: 'pipe',
- cwd: projectRoot,
- env: process.env
- });
- } catch (_) {
- return true;
- }
- return false;
- }
- function getInstalledPackages() {
- const out = {};
- if (!fs.existsSync(nodeModulesPath)) return out;
- try {
- const entries = fs.readdirSync(nodeModulesPath, { withFileTypes: true });
- for (const entry of entries) {
- if (!entry.isDirectory()) continue;
- const packageName = entry.name;
- if (packageName.startsWith('.') || packageName === 'node_modules' || packageName === 'npm' || packageName === 'corepack') continue;
- const pkgPath = path.join(nodeModulesPath, packageName, 'package.json');
- if (fs.existsSync(pkgPath)) {
- try {
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
- if (pkg.name && pkg.version) out[pkg.name.toLowerCase()] = `${pkg.name}==${pkg.version}`;
- } catch (_) {}
- }
- if (packageName.startsWith('@')) {
- try {
- const scopedPath = path.join(nodeModulesPath, packageName);
- const sub = fs.readdirSync(scopedPath, { withFileTypes: true });
- for (const e of sub) {
- if (!e.isDirectory()) continue;
- const subPath = path.join(scopedPath, e.name, 'package.json');
- if (fs.existsSync(subPath)) {
- try {
- const pkg = JSON.parse(fs.readFileSync(subPath, 'utf-8'));
- if (pkg.name && pkg.version) out[pkg.name.toLowerCase()] = `${pkg.name}==${pkg.version}`;
- } catch (_) {}
- }
- }
- } catch (_) {}
- }
- }
- } catch (_) {}
- return out;
- }
- function writeDependenciesFile(installed) {
- const lines = [...new Set(Object.values(installed))].sort();
- fs.writeFileSync(dependenciesFile, lines.join('\n') + '\n', 'utf-8');
- }
- function runUpdateOnly() {
- log('Comparing node_modules with dependencies.txt...', 'cyan');
- const installed = getInstalledPackages();
- if (Object.keys(installed).length === 0) {
- log('[ERROR] nodejs/node/node_modules not found or empty.', 'red');
- process.exit(1);
- }
- writeDependenciesFile(installed);
- log(`[OK] dependencies.txt updated (${Object.keys(installed).length} packages)`, 'green');
- }
- function main() {
- if (process.argv.includes('--update')) {
- runUpdateOnly();
- process.exit(0);
- }
- if (!fs.existsSync(path.join(projectRoot, 'package.json'))) {
- log('[X] package.json not found', 'red');
- process.exit(1);
- }
- if (!needsInstall()) {
- log('[OK] Dependencies complete, skipping npm install', 'green');
- const installed = getInstalledPackages();
- if (Object.keys(installed).length > 0) {
- writeDependenciesFile(installed);
- }
- return;
- }
- log('Running npm install...', 'cyan');
- process.chdir(projectRoot);
- const npmInstallPrefix = `--prefix ${path.join(nodeDir).replace(/\\/g, '/')}`;
- try {
- execSync(`"${npmCmd}" install ${npmInstallPrefix} --ignore-engines --no-audit`, { stdio: 'inherit', cwd: projectRoot, env: process.env });
- } catch (e) {
- log('[X] npm install failed', 'red');
- process.exit(1);
- }
- const installed = getInstalledPackages();
- writeDependenciesFile(installed);
- log(`[OK] Installed and synced to dependencies.txt (${Object.keys(installed).length} packages)`, 'green');
- }
- main();
|