180 lines
5.3 KiB
JavaScript
180 lines
5.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* This script generates a app-config.js file with environment variables
|
|
* starting with CLIENT_ for both development and production environments.
|
|
*
|
|
* It works in both local development and production environments,
|
|
* eliminating the need for a separate Docker entrypoint script.
|
|
*/
|
|
|
|
import fs from "fs";
|
|
import path from "path";
|
|
import dotenv from "dotenv";
|
|
import { fileURLToPath } from "url";
|
|
|
|
// Get the directory name in ESM
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
// Determine if we're in production or development mode
|
|
const isProduction = process.env.NODE_ENV === "production";
|
|
|
|
// Load environment variables from .env files
|
|
// In production, we prioritize .env.production and .env
|
|
// In development, we use the standard Vite hierarchy
|
|
if (isProduction) {
|
|
dotenv.config({ path: path.resolve(process.cwd(), ".env.production") });
|
|
dotenv.config({ path: path.resolve(process.cwd(), ".env") });
|
|
} else {
|
|
// Development mode - follow Vite's loading order
|
|
dotenv.config({ path: path.resolve(process.cwd(), ".env") });
|
|
dotenv.config({ path: path.resolve(process.cwd(), ".env.development") });
|
|
dotenv.config({ path: path.resolve(process.cwd(), ".env.local") });
|
|
dotenv.config({
|
|
path: path.resolve(process.cwd(), ".env.development.local"),
|
|
});
|
|
}
|
|
|
|
// Determine the target directory based on environment
|
|
// In production, we use the dist directory (or a specified output directory)
|
|
// In development, we use the public directory
|
|
const targetDir = isProduction
|
|
? process.env.OUTPUT_DIR || path.resolve(process.cwd(), "dist")
|
|
: path.resolve(process.cwd(), "public");
|
|
|
|
// Ensure the target directory exists
|
|
if (!fs.existsSync(targetDir)) {
|
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
console.log(`Created directory: ${targetDir}`);
|
|
}
|
|
|
|
// Function to convert SNAKE_CASE to camelCase
|
|
function toCamelCase(str) {
|
|
return str
|
|
.toLowerCase()
|
|
.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
}
|
|
|
|
// Create the app-config.js file
|
|
const configFilePath = path.join(targetDir, "app-config.js");
|
|
let configContent =
|
|
"// Runtime environment variables - Generated by generate-app-config.js\n";
|
|
configContent += "window.appConfig = {\n";
|
|
|
|
// Get all environment variables starting with CLIENT_
|
|
const clientEnvVars = Object.entries(process.env).filter(([key]) =>
|
|
key.startsWith("CLIENT_"),
|
|
);
|
|
|
|
// Add each environment variable to the config
|
|
clientEnvVars.forEach(([key, value]) => {
|
|
// Remove CLIENT_ prefix
|
|
const keyWithoutPrefix = key.replace(/^CLIENT_/, "");
|
|
|
|
// Convert to camelCase
|
|
const camelKey = toCamelCase(keyWithoutPrefix);
|
|
|
|
// Add the key-value pair to the config
|
|
// If the value is 'true', 'false', 'null', or a number, don't add quotes
|
|
if (
|
|
value === "true" ||
|
|
value === "false" ||
|
|
value === "null" ||
|
|
/^[0-9]+$/.test(value)
|
|
) {
|
|
configContent += ` ${camelKey}: ${value},\n`;
|
|
} else {
|
|
configContent += ` ${camelKey}: "${value}",\n`;
|
|
}
|
|
});
|
|
|
|
// Add default values for essential variables if they don't exist
|
|
if (!process.env.CLIENT_BASE_PATH) {
|
|
configContent += ' basePath: "/",\n';
|
|
}
|
|
if (!process.env.CLIENT_APP_NAME) {
|
|
configContent += ' appName: "App",\n';
|
|
}
|
|
if (!process.env.CLIENT_DEBUG) {
|
|
configContent += " debug: " + (isProduction ? "false" : "true") + ",\n";
|
|
}
|
|
|
|
// Close the object
|
|
configContent += "};";
|
|
|
|
// Helper function for colorized logging like Vite
|
|
function formatLog(label, message, color = "\x1b[36m ") {
|
|
// Default to cyan color
|
|
const reset = "\x1b[0m";
|
|
const dim = "\x1b[2m";
|
|
const arrow = `${dim}${color}➜${reset}`;
|
|
const formattedLabel = `${color}${label}:${reset}`;
|
|
return ` ${arrow} ${formattedLabel} ${message}`;
|
|
}
|
|
|
|
// Write the config file
|
|
fs.writeFileSync(configFilePath, configContent);
|
|
console.log(formatLog("Generated", `app-config.js at ${configFilePath}`));
|
|
|
|
// Check if index.html exists in the target directory
|
|
const indexHtmlPath = path.join(targetDir, "index.html");
|
|
if (fs.existsSync(indexHtmlPath)) {
|
|
let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf8");
|
|
|
|
// Check if the script tag already exists
|
|
if (!indexHtmlContent.includes("app-config.js")) {
|
|
// Insert the script tag after the opening head tag
|
|
indexHtmlContent = indexHtmlContent.replace(
|
|
"<head>",
|
|
'<head>\n <script src="./app-config.js"></script>',
|
|
);
|
|
|
|
// Write the updated index.html
|
|
fs.writeFileSync(indexHtmlPath, indexHtmlContent);
|
|
console.log(
|
|
formatLog(
|
|
"Updated",
|
|
`injected script tag into ${path.basename(indexHtmlPath)}`,
|
|
),
|
|
);
|
|
} else {
|
|
console.log(
|
|
formatLog(
|
|
"Note",
|
|
`app-config.js script already exists in ${path.basename(indexHtmlPath)}`,
|
|
"\x1b[33m ",
|
|
),
|
|
); // Yellow
|
|
}
|
|
} else {
|
|
console.log(
|
|
formatLog("Note", `index.html not found in ${targetDir}`, "\x1b[34m "),
|
|
); // Blue
|
|
if (!isProduction) {
|
|
console.log(
|
|
formatLog(
|
|
"Vite",
|
|
"script will be injected during development",
|
|
"\x1b[34m ",
|
|
),
|
|
); // Blue
|
|
} else {
|
|
console.log(
|
|
formatLog(
|
|
"Warning",
|
|
"index.html not found in production build directory!",
|
|
"\x1b[33m ",
|
|
),
|
|
); // Yellow
|
|
}
|
|
}
|
|
|
|
console.log(
|
|
formatLog(
|
|
"Ready",
|
|
`app-config generated for ${isProduction ? "production" : "development"} environment`,
|
|
"\x1b[32m ",
|
|
),
|
|
); // Green
|