#!/usr/bin/env node
/**
* This script fixes the "Maximum call stack size exceeded" error
* that occurs during Next.js build on Vercel, specifically in the
* micromatch module used by Next.js.
*/
const fs = require('fs');
const path = require('path');
// Only run this fix in Vercel environment
if (process.env.VERCEL !== '1') {
console.log('Not in Vercel environment, skipping fix');
process.exit(0);
}
console.log('Applying critical fixes for Vercel build...');
// Set Node.js options to increase memory limit
process.env.NODE_OPTIONS = process.env.NODE_OPTIONS || '';
if (!process.env.NODE_OPTIONS.includes('--max-old-space-size')) {
process.env.NODE_OPTIONS += ' --max-old-space-size=3072';
console.log(`Increased Node.js memory limit: ${process.env.NODE_OPTIONS}`);
}
// Modify next.config.js to disable problematic optimizations
try {
const nextConfigPath = path.join(process.cwd(), 'next.config.js');
if (fs.existsSync(nextConfigPath)) {
// Create a backup if it doesn't exist
const nextConfigBackup = `${nextConfigPath}.original`;
if (!fs.existsSync(nextConfigBackup)) {
fs.copyFileSync(nextConfigPath, nextConfigBackup);
console.log(`Created backup of next.config.js at ${nextConfigBackup}`);
}
// Read the current config
let nextConfig = fs.readFileSync(nextConfigPath, 'utf8');
// Simplify complex regexes in the config
nextConfig = nextConfig.replace(
/source: '\/\(.*\)\\+\.\((?:[^()]*\|)+[^()]*\)\$'/g,
'source: \'/(.*)\''
);
// Disable problematic experimental features
if (nextConfig.includes('experimental:')) {
console.log('Disabling problematic experimental features in next.config.js...');
// Disable optimizeCss experimental feature
if (nextConfig.includes('optimizeCss:')) {
nextConfig = nextConfig.replace(/optimizeCss:\s*true/, 'optimizeCss: false');
}
// Disable memoryBasedWorkersCount
if (nextConfig.includes('memoryBasedWorkersCount:')) {
nextConfig = nextConfig.replace(/memoryBasedWorkersCount:\s*true/, 'memoryBasedWorkersCount: false');
}
}
// Simplify webpack configuration if it exists
if (nextConfig.includes('webpack:')) {
console.log('Simplifying webpack configuration in next.config.js...');
// Replace the complex webpack config with a simpler one
nextConfig = nextConfig.replace(
/webpack:\s*\(config,\s*\{[^}]*\}\)\s*=>\s*\{[\s\S]*?(?=return config|config\.resolve)[\s\S]*?return config;?\s*\}/,
`webpack: (config) => {
// Simplified webpack config to avoid call stack issues
return config;
}`
);
}
// Write the simplified config
fs.writeFileSync(nextConfigPath, nextConfig);
console.log('Successfully simplified next.config.js');
}
} catch (err) {
console.error('Warning: Could not modify next.config.js:', err.message);
}
// Create a temporary .env.production.local file to disable certain features
try {
const envPath = path.join(process.cwd(), '.env.production.local');
// Add environment variables to disable problematic features
const envContent = `
# Temporary fixes to prevent Maximum call stack size exceeded
NEXT_DISABLE_SOURCEMAPS=true
NEXT_DISABLE_OPTIMIZATION=1
NEXT_TELEMETRY_DISABLED=1
NODE_ENV=production
`;
fs.writeFileSync(envPath, envContent, { flag: 'a' });
console.log('Added environment variables to disable problematic features');
} catch (err) {
console.error('Warning: Could not create .env.production.local file:', err.message);
}
// Override the micromatch module if it exists
try {
const micromatchPath = path.join(
process.cwd(),
'node_modules/next/dist/compiled/micromatch/index.js'
);
if (fs.existsSync(micromatchPath)) {
// Create a backup if it doesn't exist
const micromatchBackup = `${micromatchPath}.original`;
if (!fs.existsSync(micromatchBackup)) {
fs.copyFileSync(micromatchPath, micromatchBackup);
console.log(`Created backup of micromatch at ${micromatchBackup}`);
}
// Read the file content
const content = fs.readFileSync(micromatchPath, 'utf8');
// Skip if already patched
if (content.includes('// PATCHED TO PREVENT CALL STACK OVERFLOW')) {
console.log('Micromatch module already patched');
} else {
// Patch known problematic functions
const patchedContent = content
// Add patched flag
.replace('!function(', '// PATCHED TO PREVENT CALL STACK OVERFLOW\n!function(')
// Patch the create function to prevent deep recursion
.replace(
/(function create\(glob, options\) \{)/,
`$1
// Handle recursion depth
if (!options) options = {};
options._depth = (options._depth || 0) + 1;
if (options._depth > 50) {
return { pattern: glob, regex: new RegExp('.*') };
}`
)
// Patch the makeRe function
.replace(
/(makeRe: function\(string, options\) \{)/,
`$1
// Prevent excessive pattern complexity
if (string && string.length > 100) {
return /.*/;
}`
);
// Write the patched file
fs.writeFileSync(micromatchPath, patchedContent);
console.log('Successfully patched micromatch to prevent stack overflow');
}
}
} catch (err) {
console.error('Warning: Could not patch micromatch module:', err.message);
}
console.log('Vercel build fixes completed successfully!');