|
| 1 | +import chalk from 'chalk'; |
| 2 | +import fs from 'fs-extra'; |
| 3 | +import path from 'path'; |
| 4 | +import {Command} from 'commander/esm.mjs'; |
| 5 | + |
| 6 | +const |
| 7 | + __dirname = path.resolve(), |
| 8 | + cwd = process.cwd(), |
| 9 | + requireJson = path => JSON.parse(fs.readFileSync((path))), |
| 10 | + packageJson = requireJson(path.join(__dirname, 'package.json')), |
| 11 | + program = new Command(), |
| 12 | + programName = `${packageJson.name} copySeoFiles`; |
| 13 | + |
| 14 | +const APP_DIR = path.resolve(cwd, 'apps'); |
| 15 | +const DIST_DIR = path.resolve(cwd, 'dist'); |
| 16 | +const SEO_FILES = ['robots.txt', 'llm.txt', 'sitemap.xml']; |
| 17 | + |
| 18 | +/** |
| 19 | + * Recursively finds application root directories by looking for index.html. |
| 20 | + * Excludes 'examples' directory. |
| 21 | + * @param {string} currentDir |
| 22 | + * @returns {string[]} Array of absolute paths to app roots. |
| 23 | + */ |
| 24 | +function findAppRoots(currentDir) { |
| 25 | + let appRoots = []; |
| 26 | + const entries = fs.readdirSync(currentDir, { withFileTypes: true }); |
| 27 | + |
| 28 | + for (const entry of entries) { |
| 29 | + const fullPath = path.join(currentDir, entry.name); |
| 30 | + |
| 31 | + if (entry.isDirectory()) { |
| 32 | + // Check if current directory contains index.html |
| 33 | + if (fs.existsSync(path.join(fullPath, 'index.html'))) { |
| 34 | + appRoots.push(fullPath); |
| 35 | + } |
| 36 | + // Recurse into subdirectories |
| 37 | + appRoots = appRoots.concat(findAppRoots(fullPath)); |
| 38 | + } |
| 39 | + } |
| 40 | + return appRoots; |
| 41 | +} |
| 42 | + |
| 43 | +/** |
| 44 | + * Copies SEO files from an app root to its corresponding dist folders. |
| 45 | + * @param {string} appRootPath - Absolute path to the app's root directory. |
| 46 | + * @param {string} env - The build environment ('all', 'dev', 'prod'). |
| 47 | + */ |
| 48 | +function copySeoFilesForApp(appRootPath, env) { |
| 49 | + const appName = path.basename(appRootPath); |
| 50 | + console.log(chalk.blue(`Copying SEO files for app: ${appName}`)); |
| 51 | + |
| 52 | + const targetEnvs = []; |
| 53 | + if (env === 'all' || env === 'dev') { |
| 54 | + targetEnvs.push('development'); |
| 55 | + } |
| 56 | + if (env === 'all' || env === 'prod') { |
| 57 | + targetEnvs.push('production'); |
| 58 | + } |
| 59 | + |
| 60 | + for (const targetEnv of targetEnvs) { |
| 61 | + const targetDistDir = path.join(DIST_DIR, targetEnv, appName); |
| 62 | + if (!fs.existsSync(targetDistDir)) { |
| 63 | + console.warn(chalk.yellow(` Warning: Target directory ${targetDistDir} does not exist. Skipping SEO file copy.`)); |
| 64 | + continue; |
| 65 | + } |
| 66 | + |
| 67 | + for (const seoFile of SEO_FILES) { |
| 68 | + const sourceFilePath = path.join(appRootPath, seoFile); |
| 69 | + const targetFilePath = path.join(targetDistDir, seoFile); |
| 70 | + |
| 71 | + if (fs.existsSync(sourceFilePath)) { |
| 72 | + fs.copySync(sourceFilePath, targetFilePath); |
| 73 | + console.log(chalk.gray(` Copied ${seoFile} to ${targetDistDir}`)); |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | +} |
| 78 | + |
| 79 | +program |
| 80 | + .name(programName) |
| 81 | + .version(packageJson.version) |
| 82 | + .option('-e, --env <value>', '"all", "dev", "esm", "prod"') |
| 83 | + .allowUnknownOption() |
| 84 | + .on('--help', () => { |
| 85 | + console.log('\nIn case you have any issues, please create a ticket here:'); |
| 86 | + console.log(chalk.cyan(packageJson.bugs.url)); |
| 87 | + }) |
| 88 | + .parse(process.argv); |
| 89 | + |
| 90 | +const programOpts = program.opts(); |
| 91 | +const env = programOpts.env || 'all'; |
| 92 | + |
| 93 | +console.log(chalk.green(programName)); |
| 94 | + |
| 95 | +// --- Start SEO file copying logic --- |
| 96 | +console.log(chalk.blue('Copying SEO files for applications...')); |
| 97 | +const appRoots = findAppRoots(APP_DIR); |
| 98 | +for (const appRoot of appRoots) { |
| 99 | + copySeoFilesForApp(appRoot, env); |
| 100 | +} |
| 101 | +// --- End SEO file copying logic --- |
| 102 | + |
| 103 | +process.exit(0); |
0 commit comments