@ima/cli
Version:
IMA.js CLI tool to build, develop and work with IMA.js applications.
125 lines (124 loc) • 4.59 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.builder = exports.handler = exports.describe = exports.command = void 0;
const child_process_1 = require("child_process");
const promises_1 = __importDefault(require("fs/promises"));
const path_1 = __importDefault(require("path"));
const logger_1 = require("@ima/dev-utils/logger");
const cli_1 = require("../lib/cli");
const utils_1 = require("../webpack/utils/utils");
/**
* Wait for the server to start.
*/
async function waitForServer(port, maxAttempts = 30) {
for (let i = 0; i < maxAttempts; i++) {
try {
await fetch(`http://localhost:${port}`);
return;
}
catch {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
throw new Error('Server failed to start');
}
/**
* Prerender a single URL:
* - Fetch the HTML content
* - Return the URL and HTML content
*/
async function preRenderPath(path, baseUrl) {
const url = new URL(path, baseUrl);
const response = await fetch(url.toString());
const html = await response.text();
return { url: url.toString(), html };
}
/**
* Convert URL to filename:
* - Remove leading and trailing slashes
* - Replace remaining slashes with underscores
* - Add mode and .html extension
*/
function getOutputFilename(url, mode) {
const pathname = new URL(url).pathname;
const urlPath = pathname === '/'
? ''
: pathname.replace(/^\/|\/$/g, '').replace(/\//g, '_');
return `${mode}${urlPath ? `-${urlPath}` : ''}.html`;
}
const prerender = async (args) => {
try {
// Parse paths to prerender
const paths = args.paths
? Array.isArray(args.paths)
? args.paths
: [args.paths]
: ['/'];
// Build the application first
logger_1.logger.info('Building application...');
await (0, cli_1.runCommand)('ima', ['build'], {
...args,
});
// Load environment to get the application port
const environment = (0, utils_1.resolveEnvironment)(args.rootDir);
// Start the server with appropriate mode
const { preRenderMode } = args;
if (!preRenderMode) {
throw new Error('Prerender mode is required');
}
logger_1.logger.info(`Starting server in ${preRenderMode.toUpperCase()} mode...`);
const port = environment.$Server.port ?? 3001;
const hostname = environment.$Server.host ?? 'localhost';
const serverProcess = (0, child_process_1.spawn)('ima', ['start'], {
stdio: 'inherit',
env: {
...process.env,
...(preRenderMode === 'spa' ? { IMA_CLI_FORCE_SPA: 'true' } : {}),
},
});
// Wait for server to start
await waitForServer(port);
const baseUrl = `http://${hostname}:${port}`;
// Create output directory if it doesn't exist
const outputDir = path_1.default.resolve(args.rootDir, 'build');
await promises_1.default.mkdir(outputDir, { recursive: true });
// Prerender all URLs
logger_1.logger.info(`Prerendering ${paths.length} Path(s)...`);
const results = await Promise.all(paths.map(path => preRenderPath(path, baseUrl)));
// Write results to disk
for (const result of results) {
const outputPath = path_1.default.join(outputDir, getOutputFilename(result.url, preRenderMode));
await promises_1.default.writeFile(outputPath, result.html);
logger_1.logger.info(`Prerendered ${result.url} -> ${outputPath}`);
}
// Clean up
serverProcess.kill();
process.exit(0);
}
catch (error) {
logger_1.logger.error(error instanceof Error ? error : new Error('Unknown prerender error'));
process.exit(1);
}
};
const CMD = 'prerender';
exports.command = CMD;
exports.describe = 'Prerender application as static HTML';
exports.handler = (0, cli_1.handlerFactory)(prerender);
exports.builder = {
...(0, cli_1.sharedArgsFactory)(CMD),
preRenderMode: {
desc: 'Prerender mode (spa or ssr)',
type: 'string',
choices: ['spa', 'ssr'],
default: 'spa',
},
paths: {
desc: 'Path(s) to prerender (defaults to /)',
type: 'array',
string: true,
},
...(0, cli_1.resolveCliPluginArgs)(CMD),
};