fix: optimize i18n page generation to prevent OOM during Docker build
This commit is contained in:
@@ -26,7 +26,7 @@ ENV COMPRESSION_MODE=$COMPRESSION_MODE
|
||||
ARG BASE_URL
|
||||
ENV BASE_URL=$BASE_URL
|
||||
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
ENV NODE_OPTIONS="--max-old-space-size=3072"
|
||||
|
||||
RUN npm run build:with-docs
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build && NODE_OPTIONS='--max-old-space-size=4096' node scripts/generate-i18n-pages.mjs && node scripts/generate-sitemap.mjs",
|
||||
"build": "tsc && vite build && NODE_OPTIONS='--max-old-space-size=3072' node scripts/generate-i18n-pages.mjs && node scripts/generate-sitemap.mjs",
|
||||
"build:with-docs": "npm run build && npm run docs:build && node scripts/include-docs-in-dist.js",
|
||||
"build:gzip": "COMPRESSION_MODE=g npm run build",
|
||||
"build:brotli": "COMPRESSION_MODE=b npm run build",
|
||||
|
||||
@@ -24,6 +24,24 @@ const KEY_MAPPING = {
|
||||
404: 'notFound',
|
||||
};
|
||||
|
||||
function loadAllTranslations() {
|
||||
const translations = {};
|
||||
for (const lang of languages) {
|
||||
if (lang === 'en') continue;
|
||||
const commonPath = path.join(LOCALES_DIR, `${lang}/common.json`);
|
||||
const toolsPath = path.join(LOCALES_DIR, `${lang}/tools.json`);
|
||||
translations[lang] = {
|
||||
common: fs.existsSync(commonPath)
|
||||
? JSON.parse(fs.readFileSync(commonPath, 'utf-8'))
|
||||
: {},
|
||||
tools: fs.existsSync(toolsPath)
|
||||
? JSON.parse(fs.readFileSync(toolsPath, 'utf-8'))
|
||||
: {},
|
||||
};
|
||||
}
|
||||
return translations;
|
||||
}
|
||||
|
||||
// TODO@ALAM: Let users build only a single language
|
||||
function buildUrl(langPrefix, pagePath) {
|
||||
const parts = [SITE_URL];
|
||||
@@ -33,48 +51,20 @@ function buildUrl(langPrefix, pagePath) {
|
||||
return parts.filter(Boolean).join('/').replace(/\/+$/, '') || SITE_URL;
|
||||
}
|
||||
|
||||
async function generateI18nPages() {
|
||||
console.log('🌍 Generating i18n pages...');
|
||||
console.log(` SITE_URL: ${SITE_URL}`);
|
||||
console.log(` BASE_PATH: ${BASE_PATH || '/'}`);
|
||||
|
||||
if (!fs.existsSync(DIST_DIR)) {
|
||||
console.error('❌ dist directory not found. Please run build first.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const htmlFiles = fs
|
||||
.readdirSync(DIST_DIR)
|
||||
.filter((file) => file.endsWith('.html'));
|
||||
|
||||
for (const file of htmlFiles) {
|
||||
const filePath = path.join(DIST_DIR, file);
|
||||
const originalContent = fs.readFileSync(filePath, 'utf-8');
|
||||
function processFileForLanguage(
|
||||
originalContent,
|
||||
file,
|
||||
lang,
|
||||
translations,
|
||||
langDir
|
||||
) {
|
||||
const filenameNoExt = file.replace('.html', '');
|
||||
|
||||
let translationKey = toCamelCase(filenameNoExt);
|
||||
if (KEY_MAPPING[filenameNoExt]) {
|
||||
translationKey = KEY_MAPPING[filenameNoExt];
|
||||
}
|
||||
|
||||
for (const lang of languages) {
|
||||
if (lang === 'en') continue;
|
||||
|
||||
const langDir = path.join(DIST_DIR, lang);
|
||||
if (!fs.existsSync(langDir)) {
|
||||
fs.mkdirSync(langDir, { recursive: true });
|
||||
}
|
||||
|
||||
const commonPath = path.join(LOCALES_DIR, `${lang}/common.json`);
|
||||
const toolsPath = path.join(LOCALES_DIR, `${lang}/tools.json`);
|
||||
|
||||
const common = fs.existsSync(commonPath)
|
||||
? JSON.parse(fs.readFileSync(commonPath, 'utf-8'))
|
||||
: {};
|
||||
const tools = fs.existsSync(toolsPath)
|
||||
? JSON.parse(fs.readFileSync(toolsPath, 'utf-8'))
|
||||
: {};
|
||||
|
||||
const { tools } = translations[lang];
|
||||
const dom = new JSDOM(originalContent);
|
||||
const document = dom.window.document;
|
||||
|
||||
@@ -179,9 +169,15 @@ async function generateI18nPages() {
|
||||
link.setAttribute('href', newHref);
|
||||
});
|
||||
|
||||
fs.writeFileSync(path.join(langDir, file), dom.serialize());
|
||||
const result = dom.serialize();
|
||||
|
||||
dom.window.close();
|
||||
|
||||
fs.writeFileSync(path.join(langDir, file), result);
|
||||
}
|
||||
|
||||
function updateEnglishFile(filePath, originalContent) {
|
||||
const filenameNoExt = path.basename(filePath, '.html');
|
||||
const dom = new JSDOM(originalContent);
|
||||
const document = dom.window.document;
|
||||
|
||||
@@ -205,7 +201,68 @@ async function generateI18nPages() {
|
||||
defaultLink.href = buildUrl('', pagePath);
|
||||
document.head.appendChild(defaultLink);
|
||||
|
||||
fs.writeFileSync(filePath, dom.serialize());
|
||||
const result = dom.serialize();
|
||||
|
||||
dom.window.close();
|
||||
|
||||
fs.writeFileSync(filePath, result);
|
||||
}
|
||||
|
||||
async function generateI18nPages() {
|
||||
console.log('🌍 Generating i18n pages...');
|
||||
console.log(` SITE_URL: ${SITE_URL}`);
|
||||
console.log(` BASE_PATH: ${BASE_PATH || '/'}`);
|
||||
console.log(` Languages: ${languages.length} (${languages.join(', ')})`);
|
||||
|
||||
if (!fs.existsSync(DIST_DIR)) {
|
||||
console.error('❌ dist directory not found. Please run build first.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(' Loading translations...');
|
||||
const translations = loadAllTranslations();
|
||||
|
||||
const htmlFiles = fs
|
||||
.readdirSync(DIST_DIR)
|
||||
.filter((file) => file.endsWith('.html'));
|
||||
|
||||
console.log(` Processing ${htmlFiles.length} HTML files...`);
|
||||
|
||||
for (const lang of languages) {
|
||||
if (lang === 'en') continue;
|
||||
const langDir = path.join(DIST_DIR, lang);
|
||||
if (!fs.existsSync(langDir)) {
|
||||
fs.mkdirSync(langDir, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
let processed = 0;
|
||||
const total = htmlFiles.length * (languages.length - 1);
|
||||
|
||||
for (const file of htmlFiles) {
|
||||
const filePath = path.join(DIST_DIR, file);
|
||||
const originalContent = fs.readFileSync(filePath, 'utf-8');
|
||||
|
||||
for (const lang of languages) {
|
||||
if (lang === 'en') continue;
|
||||
|
||||
const langDir = path.join(DIST_DIR, lang);
|
||||
|
||||
processFileForLanguage(
|
||||
originalContent,
|
||||
file,
|
||||
lang,
|
||||
translations,
|
||||
langDir
|
||||
);
|
||||
|
||||
processed++;
|
||||
if (processed % 10 === 0 || processed === total) {
|
||||
console.log(` Progress: ${processed}/${total} pages`);
|
||||
}
|
||||
}
|
||||
|
||||
updateEnglishFile(filePath, originalContent);
|
||||
}
|
||||
|
||||
console.log('✅ i18n pages generated successfully!');
|
||||
|
||||
Reference in New Issue
Block a user