|
1 | 1 | import { useState } from 'react' |
2 | | -import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, Cell } from 'recharts' |
3 | | -import { BarChart3, Clock, Package } from 'lucide-react' |
| 2 | +import { BarChart3, Package, Zap } from 'lucide-react' |
4 | 3 | import './App.css' |
5 | | -import rolldownStats from '../../../rolldown-version-stats.json' |
6 | | - |
7 | | -// Utility function to format numbers with commas |
8 | | -const formatNumberWithCommas = (num: number): string => { |
9 | | - return num.toLocaleString() |
10 | | -} |
11 | | - |
12 | | -// Transform rolldown stats data for charts |
13 | | -const buildTimeData = rolldownStats.map(stat => ({ |
14 | | - name: `v${stat.version}`, |
15 | | - value: stat.buildTime |
16 | | -})) |
17 | | - |
18 | | -// Calculate bundle size differences between consecutive versions |
19 | | -const bundleSizeDiffData = rolldownStats.map((stat, index) => { |
20 | | - if (index === 0) { |
21 | | - // For the first version, show 0 difference or could show absolute value |
22 | | - return { |
23 | | - name: `v${stat.version}`, |
24 | | - value: 0, |
25 | | - previousSize: null, |
26 | | - currentSize: stat.totalSize, |
27 | | - isBaseline: true |
28 | | - } |
29 | | - } |
30 | | - |
31 | | - const prevSize = rolldownStats[index - 1].totalSize |
32 | | - const currentSize = stat.totalSize |
33 | | - const diff = currentSize - prevSize |
34 | | - |
35 | | - return { |
36 | | - name: `v${stat.version}`, |
37 | | - value: diff, |
38 | | - previousSize: prevSize, |
39 | | - currentSize: currentSize, |
40 | | - isBaseline: false |
41 | | - } |
42 | | -}) |
| 4 | +import RolldownStats from './RolldownStats' |
| 5 | +import MinificationBenchmarks from './MinificationBenchmarks' |
43 | 6 |
|
44 | 7 | function App() { |
| 8 | + const [selectedPage, setSelectedPage] = useState('rolldown') |
45 | 9 | const [selectedMetric, setSelectedMetric] = useState('bundleSize') |
46 | 10 |
|
47 | | - // Custom tooltip formatter for bundle size differences |
48 | | - const bundleSizeDiffTooltipFormatter = (value: any, name: string, props: any) => { |
49 | | - const data = props.payload |
50 | | - if (!data) return [value, name] |
51 | | - |
52 | | - if (data.isBaseline) { |
53 | | - return [`${formatNumberWithCommas(data.currentSize)} bytes (baseline)`, 'Bundle Size'] |
54 | | - } |
55 | | - |
56 | | - const sign = value >= 0 ? '+' : '' |
57 | | - const changeText = `${sign}${formatNumberWithCommas(value)} bytes` |
58 | | - const fromTo = `(${formatNumberWithCommas(data.previousSize)} → ${formatNumberWithCommas(data.currentSize)})` |
59 | | - |
60 | | - return [`${changeText} ${fromTo}`, 'Size Change'] |
61 | | - } |
62 | | - |
63 | | - const metrics = [ |
64 | | - { id: 'bundleSize', name: 'Bundle Size', icon: Package, data: bundleSizeDiffData, color: '#374151' }, |
65 | | - { id: 'buildTime', name: 'Build Time', icon: Clock, data: buildTimeData, color: '#000000' }, |
66 | | - ] |
67 | | - |
68 | | - const currentMetric = metrics.find(m => m.id === selectedMetric) || metrics[0] |
69 | | - |
70 | 11 | return ( |
71 | 12 | <div className="dashboard"> |
72 | 13 | <header className="dashboard-header"> |
73 | 14 | <div className="header-content"> |
74 | 15 | <div className="logo"> |
75 | 16 | <BarChart3 size={28} /> |
76 | | - <h1>Rolldown-Vite dashboard</h1> |
| 17 | + <h1>{selectedPage === 'rolldown' ? 'Rolldown-Vite Dashboard' : 'Minification Benchmarks'}</h1> |
77 | 18 | </div> |
78 | | - <p className="header-subtitle">Statistics collected from different Rolldown-Vite versions</p> |
| 19 | + <p className="header-subtitle"> |
| 20 | + {selectedPage === 'rolldown' |
| 21 | + ? 'Statistics collected from different Rolldown-Vite versions' |
| 22 | + : 'Performance comparison of JavaScript minification tools'} |
| 23 | + </p> |
79 | 24 | </div> |
80 | 25 | </header> |
81 | 26 |
|
82 | | - <nav className="dashboard-nav"> |
83 | | - {metrics.map((metric) => { |
84 | | - const Icon = metric.icon |
85 | | - return ( |
86 | | - <button |
87 | | - key={metric.id} |
88 | | - className={`nav-button ${selectedMetric === metric.id ? 'active' : ''}`} |
89 | | - onClick={() => { |
90 | | - setSelectedMetric(metric.id) |
91 | | - }} |
92 | | - > |
93 | | - <Icon size={20} /> |
94 | | - {metric.name} |
95 | | - </button> |
96 | | - ) |
97 | | - })} |
| 27 | + {/* Page Navigation */} |
| 28 | + <nav className="page-nav"> |
| 29 | + <button |
| 30 | + className={`page-button ${selectedPage === 'rolldown' ? 'active' : ''}`} |
| 31 | + onClick={() => { |
| 32 | + setSelectedPage('rolldown') |
| 33 | + setSelectedMetric('bundleSize') |
| 34 | + }} |
| 35 | + > |
| 36 | + <Package size={20} /> |
| 37 | + Rolldown Stats |
| 38 | + </button> |
| 39 | + <button |
| 40 | + className={`page-button ${selectedPage === 'minification' ? 'active' : ''}`} |
| 41 | + onClick={() => { |
| 42 | + setSelectedPage('minification') |
| 43 | + setSelectedMetric('minTime') |
| 44 | + }} |
| 45 | + > |
| 46 | + <Zap size={20} /> |
| 47 | + Minification Benchmarks |
| 48 | + </button> |
98 | 49 | </nav> |
99 | 50 |
|
100 | | - <main className="dashboard-main"> |
101 | | - <div className="chart-container"> |
102 | | - <h2>{currentMetric.name}</h2> |
103 | | - <ResponsiveContainer width="100%" height={400}> |
104 | | - {selectedMetric === 'bundleSize' ? ( |
105 | | - <BarChart data={currentMetric.data}> |
106 | | - <CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" /> |
107 | | - <XAxis |
108 | | - dataKey="name" |
109 | | - tick={{ fill: '#374151', fontSize: 12 }} |
110 | | - axisLine={{ stroke: '#d1d5db' }} |
111 | | - tickLine={{ stroke: '#d1d5db' }} |
112 | | - /> |
113 | | - <YAxis |
114 | | - tick={{ fill: '#374151', fontSize: 12 }} |
115 | | - axisLine={{ stroke: '#d1d5db' }} |
116 | | - tickLine={{ stroke: '#d1d5db' }} |
117 | | - /> |
118 | | - <Tooltip |
119 | | - formatter={bundleSizeDiffTooltipFormatter} |
120 | | - contentStyle={{ |
121 | | - backgroundColor: 'white', |
122 | | - border: '1px solid #d1d5db', |
123 | | - borderRadius: '0.5rem', |
124 | | - color: '#111827', |
125 | | - boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)' |
126 | | - }} |
127 | | - /> |
128 | | - <Legend |
129 | | - wrapperStyle={{ color: '#374151' }} |
130 | | - /> |
131 | | - <Bar dataKey="value" name="Bundle Size Change (bytes)"> |
132 | | - {currentMetric.data.map((entry: any, index: number) => ( |
133 | | - <Cell |
134 | | - key={`cell-${index}`} |
135 | | - fill={entry.isBaseline ? '#6b7280' : (entry.value >= 0 ? '#dc2626' : '#16a34a')} |
136 | | - /> |
137 | | - ))} |
138 | | - </Bar> |
139 | | - </BarChart> |
140 | | - ) : ( |
141 | | - <BarChart data={currentMetric.data}> |
142 | | - <CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" /> |
143 | | - <XAxis |
144 | | - dataKey="name" |
145 | | - tick={{ fill: '#374151', fontSize: 12 }} |
146 | | - axisLine={{ stroke: '#d1d5db' }} |
147 | | - tickLine={{ stroke: '#d1d5db' }} |
148 | | - /> |
149 | | - <YAxis |
150 | | - tick={{ fill: '#374151', fontSize: 12 }} |
151 | | - axisLine={{ stroke: '#d1d5db' }} |
152 | | - tickLine={{ stroke: '#d1d5db' }} |
153 | | - /> |
154 | | - <Tooltip |
155 | | - contentStyle={{ |
156 | | - backgroundColor: 'white', |
157 | | - border: '1px solid #d1d5db', |
158 | | - borderRadius: '0.5rem', |
159 | | - color: '#111827', |
160 | | - boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)' |
161 | | - }} |
162 | | - /> |
163 | | - <Legend |
164 | | - wrapperStyle={{ color: '#374151' }} |
165 | | - /> |
166 | | - <Bar |
167 | | - dataKey="value" |
168 | | - fill="url(#buildTimeGradient)" |
169 | | - name="Build Time (ms)" |
170 | | - /> |
171 | | - <defs> |
172 | | - <linearGradient id="buildTimeGradient" x1="0" y1="0" x2="0" y2="1"> |
173 | | - <stop offset="0%" stopColor="#000000" stopOpacity={1}/> |
174 | | - <stop offset="100%" stopColor="#374151" stopOpacity={0.8}/> |
175 | | - </linearGradient> |
176 | | - </defs> |
177 | | - </BarChart> |
178 | | - )} |
179 | | - </ResponsiveContainer> |
180 | | - </div> |
181 | | - |
182 | | - <div className="stats-grid"> |
183 | | - <div className="stat-card"> |
184 | | - <h3>Average Build Time</h3> |
185 | | - <p className="stat-value">{Math.round(buildTimeData.reduce((sum, item) => sum + item.value, 0) / buildTimeData.length)}ms</p> |
186 | | - <span className="stat-change positive">Across {buildTimeData.length} versions</span> |
187 | | - </div> |
188 | | - <div className="stat-card"> |
189 | | - <h3>Latest Bundle Size</h3> |
190 | | - <p className="stat-value">{formatNumberWithCommas(rolldownStats[rolldownStats.length - 1]?.totalSize || 0)} bytes</p> |
191 | | - <span className="stat-change positive">v{rolldownStats[rolldownStats.length - 1]?.version}</span> |
192 | | - </div> |
193 | | - <div className="stat-card"> |
194 | | - <h3>Bundle Size Range</h3> |
195 | | - <p className="stat-value">{Math.round((Math.max(...rolldownStats.map(s => s.totalSize)) - Math.min(...rolldownStats.map(s => s.totalSize))) / 1024)}KB</p> |
196 | | - <span className="stat-change positive">Size Variation</span> |
197 | | - </div> |
198 | | - <div className="stat-card"> |
199 | | - <h3>Versions Tested</h3> |
200 | | - <p className="stat-value">{rolldownStats.length}</p> |
201 | | - <span className="stat-change positive">{rolldownStats[0]?.version} - {rolldownStats[rolldownStats.length - 1]?.version}</span> |
202 | | - </div> |
203 | | - </div> |
204 | | - </main> |
| 51 | + {/* Render the appropriate component based on selected page */} |
| 52 | + {selectedPage === 'rolldown' ? ( |
| 53 | + <RolldownStats |
| 54 | + selectedMetric={selectedMetric} |
| 55 | + setSelectedMetric={setSelectedMetric} |
| 56 | + /> |
| 57 | + ) : ( |
| 58 | + <MinificationBenchmarks |
| 59 | + selectedMetric={selectedMetric} |
| 60 | + setSelectedMetric={setSelectedMetric} |
| 61 | + /> |
| 62 | + )} |
205 | 63 | </div> |
206 | 64 | ) |
207 | 65 | } |
|
0 commit comments