UNPKG

@ordojs/cli

Version:

Command-line interface for OrdoJS framework

285 lines (270 loc) 9.83 kB
/** * @fileoverview OrdoJS CLI - Vercel deployment adapter * Adapter for deploying to Vercel */ import path from 'path'; import { AssetOptimizer, OptimizationResults } from '../../asset-optimizer.js'; import { mkdir, writeFile } from '../../fs.js'; import { logger } from '../../logger.js'; import { DeploymentAdapter, DeploymentConfig, DeploymentResult } from '../adapter-interface.js'; /** * Vercel deployment adapter */ export class VercelAdapter { /** * Adapter name */ name = 'vercel'; /** * Adapter description */ description = 'Deploy to Vercel'; /** * Validate Vercel deployment configuration * @param config Deployment configuration * @returns Validation result */ validateConfig(config) { const errors = []; // Check required fields if (!config.outputDir) { errors.push('outputDir is required'); } // Validate Vercel-specific settings const vercelConfig = config; if (vercelConfig.settings) { // Validate project name if provided if (vercelConfig.settings.projectName && !/^[a-z0-9-]+$/.test(vercelConfig.settings.projectName)) { errors.push('Project name must contain only lowercase letters, numbers, and hyphens'); } // Validate Node.js version if provided if (vercelConfig.settings.nodeVersion && !/^[0-9]+\.[0-9]+\.[0-9]+$|^[0-9]+$/.test(vercelConfig.settings.nodeVersion)) { errors.push('Invalid Node.js version format'); } } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : undefined }; } /** * Prepare Vercel deployment * @param config Deployment configuration * @returns Deployment result */ async prepareDeployment(config) { const vercelConfig = config; const generatedFiles = []; try { // Create vercel.json configuration const vercelJsonContent = this.generateVercelConfig(vercelConfig); const vercelJsonPath = path.join(config.outputDir, 'vercel.json'); await writeFile(vercelJsonPath, vercelJsonContent); generatedFiles.push({ path: vercelJsonPath, content: vercelJsonContent }); // Create build output directory if it doesn't exist await mkdir(config.outputDir, { recursive: true }); // Generate .vercel directory with project.json const projectJsonContent = this.generateProjectConfig(vercelConfig); const projectJsonDir = path.join(config.outputDir, '.vercel'); const projectJsonPath = path.join(projectJsonDir, 'project.json'); await mkdir(projectJsonDir, { recursive: true }); await writeFile(projectJsonPath, projectJsonContent); generatedFiles.push({ path: projectJsonPath, content: projectJsonContent }); // Generate server functions if needed if (config.includeServerFunctions) { await this.generateServerFunctions(config); } // Optimize assets for Vercel const optimizationResults = await this.optimizeForDeployment(config, config.outputDir); return { success: true, generatedFiles, instructions: this.getDeploymentInstructions(vercelConfig), optimizationResults }; } catch (error) { logger.error(`Vercel deployment preparation failed: ${error instanceof Error ? error.message : String(error)}`); return { success: false, error: `Vercel deployment preparation failed: ${error instanceof Error ? error.message : String(error)}`, generatedFiles, instructions: 'An error occurred during Vercel deployment preparation. Please check the logs for details.' }; } } /** * Generate Vercel configuration * @param config Vercel configuration * @returns Vercel configuration JSON */ generateVercelConfig(config) { const vercelConfig = { version: 2, buildCommand: 'ordojs build --production', outputDirectory: config.outputDir, framework: config.settings?.framework || 'ordojs', regions: config.settings?.region ? [config.settings.region] : ['iad1'], env: config.env || {} }; // Add headers if provided if (config.headers && config.headers.length > 0) { vercelConfig.headers = config.headers; } // Add redirects if provided if (config.redirects && config.redirects.length > 0) { vercelConfig.redirects = config.redirects; } // Add routes for API functions if needed if (config.includeServerFunctions) { vercelConfig.routes = [ { src: '/api/(.*)', dest: '/api/$1' } ]; } return JSON.stringify(vercelConfig, null, 2); } /** * Generate Vercel project configuration * @param config Vercel configuration * @returns Project configuration JSON */ generateProjectConfig(config) { const projectConfig = { projectId: config.settings?.projectName || 'ordojs-app', orgId: 'your-org-id', settings: { framework: config.settings?.framework || 'ordojs', nodeVersion: config.settings?.nodeVersion || '18.x' } }; return JSON.stringify(projectConfig, null, 2); } /** * Generate server functions for Vercel * @param config Deployment configuration */ async generateServerFunctions(config) { // Create api directory const apiDir = path.join(config.outputDir, 'api'); await mkdir(apiDir, { recursive: true }); // Generate example API function const exampleFunctionContent = ` export default function handler(req, res) { res.status(200).json({ message: 'Hello from OrdoJS on Vercel!', timestamp: new Date().toISOString() }); } `; await writeFile(path.join(apiDir, 'hello.js'), exampleFunctionContent); } /** * Get deployment instructions * @param config Vercel configuration * @returns Deployment instructions */ getDeploymentInstructions(config) { return ` # Vercel Deployment Instructions Your project has been prepared for deployment to Vercel. ## Prerequisites 1. Install the Vercel CLI: \`\`\` npm install -g vercel \`\`\` 2. Login to Vercel: \`\`\` vercel login \`\`\` ## Deployment To deploy your application to Vercel, run: \`\`\` cd ${config.outputDir} vercel --prod \`\`\` ## Configuration The following files have been generated: - \`vercel.json\`: Vercel configuration file - \`.vercel/project.json\`: Project configuration You can customize these files to adjust your deployment settings. ## Environment Variables ${config.env && Object.keys(config.env).length > 0 ? 'The following environment variables have been configured:\n\n' + Object.entries(config.env).map(([key, value]) => `- ${key}: ${value}`).join('\n') : 'No environment variables have been configured. You can add them in the Vercel dashboard or in the vercel.json file.'} ## Custom Domain ${config.domain ? `Your application will be available at: ${config.domain.name}` : 'You can configure a custom domain in the Vercel dashboard after deployment.'} `; } /** * Optimize assets for Vercel deployment * @param config Deployment configuration * @param outputDir Output directory * @returns Optimization results */ async optimizeForDeployment(config, outputDir) { logger.info('Optimizing assets for Vercel deployment...'); // Initialize asset optimizer with Vercel-specific options const optimizer = new AssetOptimizer({ minifyJs: true, minifyCss: true, brotli: true, gzip: true, sizeReport: true, terserOptions: { compress: { passes: 2, drop_console: true, drop_debugger: true }, mangle: true, format: { comments: false } } }); // Optimize all assets in the output directory const optimizationResults = await optimizer.optimizeDirectory(outputDir); // Generate and save size report const sizeReport = optimizer.generateSizeReport(optimizationResults); await writeFile(path.join(outputDir, 'size-report.txt'), sizeReport); return optimizationResults; } /** * Get Vercel-specific environment variables * @param config Deployment configuration * @returns Environment variables */ getEnvironmentVariables(config) { const env = { VERCEL: '1', NODE_ENV: 'production', ...config.env }; // Add Vercel-specific environment variables if (config.domain) { env.VERCEL_URL = config.domain.name; } return env; } /** * Get Vercel deployment command * @param config Deployment configuration * @returns Deployment command */ getDeployCommand(config) { return `cd ${config.outputDir} && vercel --prod`; } } //# sourceMappingURL=vercel-adapter.js.map