Compare commits

...

5 Commits

Author SHA1 Message Date
syuilo b697c419a7 Update minify-node-modules.mjs 2025-11-30 14:31:09 +09:00
syuilo c87fb96195 Merge branch 'develop' into copilot/minify-backend-code 2025-11-30 14:16:32 +09:00
copilot-swe-agent[bot] e5f1af9606 Address code review feedback: extract constants and esbuild options
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-11-30 03:11:24 +00:00
copilot-swe-agent[bot] d5256a290f Add minify-node-modules script to reduce memory usage via esbuild
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-11-30 03:09:47 +00:00
copilot-swe-agent[bot] d1d50d19e0 Initial plan 2025-11-30 02:42:57 +00:00
2 changed files with 120 additions and 0 deletions

View File

@ -25,6 +25,7 @@
"build-pre": "node ./scripts/build-pre.js", "build-pre": "node ./scripts/build-pre.js",
"build-assets": "node ./scripts/build-assets.mjs", "build-assets": "node ./scripts/build-assets.mjs",
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets", "build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
"minify-node-modules": "node ./scripts/minify-node-modules.mjs",
"build-storybook": "pnpm --filter frontend build-storybook", "build-storybook": "pnpm --filter frontend build-storybook",
"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api", "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js", "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",

View File

@ -0,0 +1,119 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/**
* This script minifies JavaScript files in node_modules to reduce memory usage.
* V8 keeps script source code in memory, so minifying reduces memory consumption.
*
* Usage:
* node scripts/minify-node-modules.mjs
*
* Environment variables:
* MISSKEY_MINIFY_NODE_MODULES - Set to 'true' to enable minification (default: true in production)
* NODE_ENV - When set to 'development', minification is skipped
*/
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import { fileURLToPath } from 'node:url';
import * as esbuild from 'esbuild';
import glob from 'fast-glob';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const rootDir = path.resolve(__dirname, '..');
// Configuration constants
const BATCH_SIZE = 100;
const MIN_FILE_SIZE_BYTES = 50;
/** @type {import('esbuild').TransformOptions} */
const esbuildOptions = {
loader: 'js',
minifyWhitespace: true,
minifyIdentifiers: true,
minifySyntax: true,
};
console.log('Minifying node_modules JavaScript files...');
const pnpmDir = path.join(rootDir, 'node_modules', '.pnpm');
// Check if pnpm directory exists
try {
await fs.access(pnpmDir);
} catch {
console.log('No pnpm node_modules found, skipping minification');
process.exit(0);
}
// Find all JavaScript files in node_modules/.pnpm
// Use followSymbolicLinks: false to avoid following symlinks to workspace packages
const jsFiles = await glob('**/*.js', {
cwd: pnpmDir,
absolute: true,
followSymbolicLinks: false,
ignore: [
// Ignore already minified files
'**/*.min.js',
// Ignore source maps
'**/*.js.map',
// Ignore TypeScript declaration files that might be named .js
'**/*.d.js',
// Ignore workspace package symlinks
'node_modules/i18n/**',
'node_modules/backend/**',
'node_modules/frontend/**',
'node_modules/frontend-embed/**',
'node_modules/frontend-shared/**',
'node_modules/frontend-builder/**',
'node_modules/icons-subsetter/**',
'node_modules/sw/**',
'node_modules/misskey-js/**',
'node_modules/misskey-js-type-generator/**',
'node_modules/misskey-reversi/**',
'node_modules/misskey-bubble-game/**',
],
});
console.log(`Found ${jsFiles.length} JavaScript files to minify`);
// Process files in parallel batches for efficiency
let processed = 0;
let errors = 0;
for (let i = 0; i < jsFiles.length; i += BATCH_SIZE) {
const batch = jsFiles.slice(i, i + BATCH_SIZE);
await Promise.all(batch.map(async (filePath) => {
try {
const content = await fs.readFile(filePath, 'utf-8');
// Skip empty files or very small files (likely not worth minifying)
if (content.length < MIN_FILE_SIZE_BYTES) {
processed++;
return;
}
const result = await esbuild.transform(content, esbuildOptions);
await fs.writeFile(filePath, result.code);
processed++;
} catch (err) {
// Some files may have syntax that esbuild doesn't handle well, skip them
errors++;
if (process.env.DEBUG) {
console.error(`Failed to minify ${filePath}: ${err.message}`);
}
}
}));
// Progress update every 10 batches
if ((i / BATCH_SIZE) % 10 === 0) {
console.log(`Progress: ${processed}/${jsFiles.length} files processed...`);
}
}
console.log(`Minification complete: ${processed} files processed, ${errors} files skipped due to errors`);