next.js / scripts /analyze-dev-server-bundle.js
AbdulElahGwaith's picture
Upload folder using huggingface_hub
b91e262 verified
#!/usr/bin/env node
/**
* Dev Server Bundle Analyzer
*
* Generates a bundle analyzer report for the dev server bundle.
*
* Usage:
* node scripts/analyze-bundle.js [options]
*
* Options:
* --open Open the report in browser (default: false)
* --verbose Show detailed module reasons
* --json Also output stats.json file
* --list-modules List all bundled modules to console
* --list-externals List all externalized modules
*/
const { execSync } = require('child_process')
const path = require('path')
const fs = require('fs')
// Parse arguments
const args = process.argv.slice(2)
const hasFlag = (name) => args.includes(`--${name}`)
const openBrowser = hasFlag('open')
const verbose = hasFlag('verbose')
const outputJson = hasFlag('json')
const listModules = hasFlag('list-modules')
const listExternals = hasFlag('list-externals')
const nextDir = path.join(__dirname, '..', 'packages', 'next')
const bundlePath = path.join(
nextDir,
'dist/compiled/dev-server/start-server.js'
)
const reportPath = path.join(
nextDir,
'dist/compiled/dev-server/bundle-report.html'
)
console.log('\x1b[34m=== Dev Server Bundle Analyzer ===\x1b[0m')
console.log('')
// Build with analyzer
console.log('Building bundle with analyzer...')
const env = {
...process.env,
ANALYZE: '1',
...(verbose ? { ANALYZE_REASONS: '1' } : {}),
}
try {
execSync('npx taskr next_bundle_dev_server', {
cwd: nextDir,
stdio: verbose ? 'inherit' : 'pipe',
env,
})
} catch (err) {
console.error('\x1b[31mBuild failed\x1b[0m')
process.exit(1)
}
// Get bundle stats
const stats = fs.statSync(bundlePath)
const sizeKB = Math.round(stats.size / 1024)
const sizeMB = (stats.size / (1024 * 1024)).toFixed(2)
console.log('')
console.log('\x1b[32mBundle Stats:\x1b[0m')
console.log(` Size: ${sizeKB} KB (${sizeMB} MB)`)
console.log(` Path: ${bundlePath}`)
console.log(` Report: ${reportPath}`)
console.log('')
// List bundled modules
if (listModules) {
console.log('\x1b[33mBundled Modules:\x1b[0m')
const content = fs.readFileSync(bundlePath, 'utf-8')
const moduleMatches = content.match(/"\.\/dist\/[^"]+/g) || []
const modules = [...new Set(moduleMatches)]
.map((m) => m.replace(/^"/, ''))
.filter((m) => !m.includes(' recursive'))
.sort()
modules.forEach((m) => console.log(` ${m}`))
console.log(`\n Total: ${modules.length} modules`)
console.log('')
}
// List externalized modules
if (listExternals) {
console.log('\x1b[33mExternalized Modules:\x1b[0m')
const content = fs.readFileSync(bundlePath, 'utf-8')
// Find external requires
const externalMatches =
content.match(
/require\("(next\/dist\/[^"]+|@next\/[^"]+|styled-jsx[^"]*)"\)/g
) || []
const externals = [...new Set(externalMatches)]
.map((m) => m.match(/require\("([^"]+)"\)/)[1])
.sort()
externals.forEach((m) => console.log(` ${m}`))
console.log(`\n Total: ${externals.length} external requires`)
console.log('')
}
// Output JSON stats
if (outputJson) {
const statsJsonPath = path.join(
nextDir,
'dist/compiled/dev-server/stats.json'
)
console.log(`Stats JSON: ${statsJsonPath}`)
console.log('(Run with ANALYZE_REASONS=1 for detailed stats)')
}
// Open in browser
if (openBrowser) {
console.log('Opening report in browser...')
const opener =
process.platform === 'darwin'
? 'open'
: process.platform === 'win32'
? 'start'
: 'xdg-open'
try {
execSync(`${opener} "${reportPath}"`, { stdio: 'ignore' })
} catch {
console.log(`Could not open browser. Open manually: ${reportPath}`)
}
}
console.log('\x1b[32mDone!\x1b[0m')
console.log('')
console.log('Tips:')
console.log(' - Open the HTML report to see interactive treemap')
console.log(' - Use --list-modules to see all bundled modules')
console.log(' - Use --list-externals to see external requires')
console.log(' - Use --verbose for detailed build output')