| | #!/usr/bin/env node |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | const { execSync } = require('child_process') |
| | const path = require('path') |
| | const fs = require('fs') |
| |
|
| | |
| | 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('') |
| |
|
| | |
| | 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) |
| | } |
| |
|
| | |
| | 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('') |
| |
|
| | |
| | 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('') |
| | } |
| |
|
| | |
| | if (listExternals) { |
| | console.log('\x1b[33mExternalized Modules:\x1b[0m') |
| | const content = fs.readFileSync(bundlePath, 'utf-8') |
| |
|
| | |
| | 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('') |
| | } |
| |
|
| | |
| | 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)') |
| | } |
| |
|
| | |
| | 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') |
| |
|