init commit

This commit is contained in:
2025-10-19 18:27:00 +09:00
commit 150891b29d
219 changed files with 70016 additions and 0 deletions

View File

@@ -0,0 +1,279 @@
#!/usr/bin/env node
/**
* Build script for production deployment
* Handles CSS compilation, asset optimization, and production setup
*/
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
// Configuration
const BUILD_DIR = path.join(__dirname, '..', 'dist');
const PUBLIC_DIR = path.join(__dirname, '..', 'public');
const VIEWS_DIR = path.join(__dirname, '..', 'views');
async function buildForProduction() {
try {
console.log('🏗️ Starting production build...');
// Create build directory
await createBuildDirectory();
// Install production dependencies
await installProductionDependencies();
// Optimize assets
await optimizeAssets();
// Generate service worker with workbox
await generateServiceWorker();
// Create production environment file
await createProductionEnv();
// Copy necessary files
await copyProductionFiles();
console.log('✅ Production build completed successfully!');
console.log('📦 Build output available in:', BUILD_DIR);
console.log('🚀 Ready for deployment!');
} catch (error) {
console.error('❌ Production build failed:', error);
process.exit(1);
}
}
async function createBuildDirectory() {
try {
if (fs.existsSync(BUILD_DIR)) {
console.log('🗑️ Cleaning existing build directory...');
await execAsync(`rm -rf ${BUILD_DIR}`);
}
fs.mkdirSync(BUILD_DIR, { recursive: true });
console.log('📁 Created build directory');
} catch (error) {
console.error('❌ Error creating build directory:', error);
throw error;
}
}
async function installProductionDependencies() {
try {
console.log('📦 Installing production dependencies...');
await execAsync('npm ci --only=production');
console.log('✅ Production dependencies installed');
} catch (error) {
console.error('❌ Error installing dependencies:', error);
throw error;
}
}
async function optimizeAssets() {
try {
console.log('🎨 Optimizing CSS and JavaScript...');
// Create optimized CSS
const cssContent = fs.readFileSync(path.join(PUBLIC_DIR, 'css', 'main.css'), 'utf8');
const optimizedCSS = await optimizeCSS(cssContent);
const buildCSSDir = path.join(BUILD_DIR, 'public', 'css');
fs.mkdirSync(buildCSSDir, { recursive: true });
fs.writeFileSync(path.join(buildCSSDir, 'main.min.css'), optimizedCSS);
// Create optimized JavaScript
const jsContent = fs.readFileSync(path.join(PUBLIC_DIR, 'js', 'main.js'), 'utf8');
const optimizedJS = await optimizeJS(jsContent);
const buildJSDir = path.join(BUILD_DIR, 'public', 'js');
fs.mkdirSync(buildJSDir, { recursive: true });
fs.writeFileSync(path.join(buildJSDir, 'main.min.js'), optimizedJS);
// Copy other assets
await copyDirectory(path.join(PUBLIC_DIR, 'images'), path.join(BUILD_DIR, 'public', 'images'));
console.log('✅ Assets optimized');
} catch (error) {
console.error('❌ Error optimizing assets:', error);
throw error;
}
}
async function optimizeCSS(css) {
// Simple CSS minification (remove comments, extra whitespace)
return css
.replace(/\/\*[\s\S]*?\*\//g, '') // Remove comments
.replace(/\s{2,}/g, ' ') // Replace multiple spaces with single space
.replace(/;\s*}/g, '}') // Remove semicolon before closing brace
.replace(/\s*{\s*/g, '{') // Remove spaces around opening brace
.replace(/;\s*/g, ';') // Remove spaces after semicolons
.replace(/,\s*/g, ',') // Remove spaces after commas
.trim();
}
async function optimizeJS(js) {
// Simple JS minification (remove comments, extra whitespace)
return js
.replace(/\/\/.*$/gm, '') // Remove single-line comments
.replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
.replace(/\s{2,}/g, ' ') // Replace multiple spaces with single space
.replace(/\n\s*/g, '') // Remove newlines and indentation
.trim();
}
async function generateServiceWorker() {
try {
console.log('⚙️ Generating optimized service worker...');
const swContent = fs.readFileSync(path.join(PUBLIC_DIR, 'sw.js'), 'utf8');
const optimizedSW = await optimizeJS(swContent);
fs.writeFileSync(path.join(BUILD_DIR, 'public', 'sw.js'), optimizedSW);
// Copy manifest
fs.copyFileSync(
path.join(PUBLIC_DIR, 'manifest.json'),
path.join(BUILD_DIR, 'public', 'manifest.json')
);
console.log('✅ Service worker generated');
} catch (error) {
console.error('❌ Error generating service worker:', error);
throw error;
}
}
async function createProductionEnv() {
try {
console.log('🔧 Creating production environment configuration...');
const prodEnv = `
# Production Environment Configuration
NODE_ENV=production
PORT=3000
# Database
MONGODB_URI=mongodb://localhost:27017/smartsoltech
# Security
SESSION_SECRET=your-super-secret-session-key-change-this-in-production
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
# File Upload
UPLOAD_PATH=./uploads
MAX_FILE_SIZE=10485760
# Email Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
# Telegram Bot (Optional)
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
# Admin Account
ADMIN_EMAIL=admin@smartsoltech.kr
ADMIN_PASSWORD=change-this-password
# Security Headers
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
`.trim();
fs.writeFileSync(path.join(BUILD_DIR, '.env.production'), prodEnv);
console.log('✅ Production environment file created');
} catch (error) {
console.error('❌ Error creating production environment:', error);
throw error;
}
}
async function copyProductionFiles() {
try {
console.log('📋 Copying production files...');
// Copy main application files
const filesToCopy = [
'server.js',
'package.json',
'package-lock.json'
];
for (const file of filesToCopy) {
fs.copyFileSync(
path.join(__dirname, '..', file),
path.join(BUILD_DIR, file)
);
}
// Copy directories
await copyDirectory(
path.join(__dirname, '..', 'models'),
path.join(BUILD_DIR, 'models')
);
await copyDirectory(
path.join(__dirname, '..', 'routes'),
path.join(BUILD_DIR, 'routes')
);
await copyDirectory(
path.join(__dirname, '..', 'views'),
path.join(BUILD_DIR, 'views')
);
await copyDirectory(
path.join(__dirname, '..', 'middleware'),
path.join(BUILD_DIR, 'middleware')
);
// Create uploads directory
fs.mkdirSync(path.join(BUILD_DIR, 'uploads'), { recursive: true });
console.log('✅ Production files copied');
} catch (error) {
console.error('❌ Error copying production files:', error);
throw error;
}
}
async function copyDirectory(src, dest) {
try {
if (!fs.existsSync(src)) {
return;
}
fs.mkdirSync(dest, { recursive: true });
const items = fs.readdirSync(src);
for (const item of items) {
const srcPath = path.join(src, item);
const destPath = path.join(dest, item);
const stat = fs.statSync(srcPath);
if (stat.isDirectory()) {
await copyDirectory(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
}
}
} catch (error) {
console.error(`❌ Error copying directory ${src}:`, error);
throw error;
}
}
if (require.main === module) {
buildForProduction();
}
module.exports = { buildForProduction };