Bundle Optimization
Drizzle Cube is designed with bundle optimization in mind, providing modular architecture that allows you to import only what you need for optimal performance and smaller bundle sizes.
Modular Architecture
Section titled “Modular Architecture”The client is built with multiple entry points, allowing fine-grained control over what gets included in your bundle:
| Import Path | Size | Dependencies | Use Case |
|---|---|---|---|
drizzle-cube/client | Full bundle | All | Complete dashboard apps |
drizzle-cube/client/charts | ~550 bytes + chunks | Recharts | Custom UI with charts |
drizzle-cube/client/hooks | ~3.2KB | None | Headless data fetching |
drizzle-cube/client/providers | ~190 bytes + chunks | None | Custom implementations |
drizzle-cube/client/components | ~218KB | react-grid-layout | Dashboard UI without charts |
drizzle-cube/client/utils | ~40 bytes | None | Helper functions only |
Bundle Size Comparison
Section titled “Bundle Size Comparison”Before Optimization (Traditional Approach)
Section titled “Before Optimization (Traditional Approach)”import { AnalyticsDashboard } from 'drizzle-cube/client';// Bundle: ~1MB+ (includes everything)After Optimization (Modular Approach)
Section titled “After Optimization (Modular Approach)”// Charts only: ~550 bytes + Recharts chunk (~86KB)import { RechartsBarChart } from 'drizzle-cube/client/charts';
// Hooks only: ~3.2KBimport { useCubeQuery } from 'drizzle-cube/client/hooks';
// Providers only: ~190 bytes + React chunk (~5.5KB)import { CubeProvider } from 'drizzle-cube/client/providers';Result: ~89KB total vs ~1MB+ (91% reduction)
Optimization Strategies
Section titled “Optimization Strategies”1. Chart-Only Applications
Section titled “1. Chart-Only Applications”Perfect for apps that need visualizations with custom UI:
// package.json{ "dependencies": { "drizzle-cube": "^0.2.4", "react": "^18.0.0", "react-dom": "^18.0.0", "recharts": "^3.5.1" // No react-grid-layout needed }}import { RechartsBarChart, RechartsLineChart, RechartsAreaChart } from 'drizzle-cube/client/charts';import { useCubeQuery } from 'drizzle-cube/client/hooks';import { CubeProvider } from 'drizzle-cube/client/providers';
function CustomDashboard() { return ( <CubeProvider apiOptions={{ apiUrl: '/api/cube' }}> <div className="grid grid-cols-2 gap-4"> <div className="bg-white p-4 rounded shadow"> <h3>Sales by Category</h3> <ChartWithQuery chart={RechartsBarChart} query={{ measures: ['Sales.revenue'], dimensions: ['Sales.category'] }} /> </div> <div className="bg-white p-4 rounded shadow"> <h3>Trend Over Time</h3> <ChartWithQuery chart={RechartsLineChart} query={{ measures: ['Sales.revenue'], timeDimensions: [{ dimension: 'Sales.date', granularity: 'month' }] }} /> </div> </div> </CubeProvider> );}
function ChartWithQuery({ chart: Chart, query }) { const { data, isLoading } = useCubeQuery(query); if (isLoading) return <div>Loading...</div>; return <Chart data={data} chartConfig={{ x: Object.keys(data[0])[0], y: [Object.keys(data[0])[1]] }} />;}Bundle savings: ~800KB+ (no grid layout, no extra components)
2. Headless Data Applications
Section titled “2. Headless Data Applications”For completely custom UI implementations:
// package.json - minimal dependencies{ "dependencies": { "drizzle-cube": "^0.2.4", "react": "^18.0.0", "react-dom": "^18.0.0" // No chart or layout dependencies }}import { useCubeQuery, useCubeMetaQuery } from 'drizzle-cube/client/hooks';import { CubeProvider } from 'drizzle-cube/client/providers';
function HeadlessAnalytics() { return ( <CubeProvider apiOptions={{ apiUrl: '/api/cube' }}> <CustomMetrics /> <CustomTable /> </CubeProvider> );}
function CustomMetrics() { const { data, isLoading } = useCubeQuery({ measures: ['Sales.revenue', 'Sales.count'], dimensions: ['Sales.category'] });
if (isLoading) return <div>Loading metrics...</div>;
return ( <div className="grid grid-cols-3 gap-4"> {data?.map(row => ( <div key={row.category} className="bg-blue-50 p-4 rounded"> <h3 className="font-bold">{row['Sales.category']}</h3> <p className="text-2xl">${row['Sales.revenue']}</p> <p className="text-sm text-gray-600">{row['Sales.count']} orders</p> </div> ))} </div> );}Bundle savings: ~950KB+ (no charts, no grid layout, no extra UI)
3. Mixed Approach
Section titled “3. Mixed Approach”Combine modular imports for optimal bundle size:
// Import only what you needimport { AnalysisBuilder } from 'drizzle-cube/client'; // Dashboard builderimport { RechartsBarChart, RechartsLineChart } from 'drizzle-cube/client/charts'; // Specific chartsimport { useCubeQuery } from 'drizzle-cube/client/hooks'; // Data fetchingimport { CubeProvider } from 'drizzle-cube/client/providers'; // Context
function MixedApp() { return ( <CubeProvider apiOptions={{ apiUrl: '/api/cube' }}> <div className="grid grid-cols-2 gap-8"> <div> <h2>Query Builder</h2> <AnalysisBuilder /> </div> <div> <h2>Custom Charts</h2> <CustomChartsPanel /> </div> </div> </CubeProvider> );}Bundle size: Only includes AnalysisBuilder component + specific charts (saves ~200KB+ vs full import)
Chunk Optimization
Section titled “Chunk Optimization”The build system automatically creates optimized chunks:
Automatic Chunking
Section titled “Automatic Chunking”dist/client/├── charts.js # Chart entry point (~550 bytes)├── hooks.js # Hooks entry point (~3.2KB)├── providers.js # Providers entry point (~190 bytes)├── components.js # Components entry point (~218KB)├── chunks/│ ├── recharts-[hash].js # Recharts library (~86KB)│ ├── layout-[hash].js # react-grid-layout (~35KB)│ ├── icons-[hash].js # Icon libraries (~50KB)│ └── providers-[hash].js # Shared providers (~5.5KB)Chunk Loading Strategy
Section titled “Chunk Loading Strategy”- Entry points load immediately (small)
- Heavy dependencies load on demand (chunked)
- Shared utilities cached across components
- Unused chunks never loaded
Performance Tips
Section titled “Performance Tips”1. Tree Shaking Configuration
Section titled “1. Tree Shaking Configuration”Ensure your bundler (Vite, Webpack) is configured for optimal tree shaking:
export default { build: { rollupOptions: { treeshake: { moduleSideEffects: false, propertyReadSideEffects: false, unknownGlobalSideEffects: false } } }}2. Dynamic Imports
Section titled “2. Dynamic Imports”Load chart components dynamically:
import { lazy, Suspense } from 'react';
const RechartsBarChart = lazy(() => import('drizzle-cube/client/charts').then(m => ({ default: m.RechartsBarChart })));
function LazyChart() { return ( <Suspense fallback={<div>Loading chart...</div>}> <RechartsBarChart data={data} config={config} /> </Suspense> );}3. Selective CSS Imports
Section titled “3. Selective CSS Imports”Import only the styles you need:
// Full stylesimport 'drizzle-cube/client/styles.css';
// Or configure Tailwind to purge unused styles// tailwind.config.jsmodule.exports = { content: ['./src/**/*.{js,ts,jsx,tsx}'], // Tailwind will automatically purge unused classes}Bundle Analysis
Section titled “Bundle Analysis”Analyze Your Bundle
Section titled “Analyze Your Bundle”Use the included bundle analyzer:
npm run analyze:client# Opens dist/client-bundle-stats.html in browserMeasure Impact
Section titled “Measure Impact”Before optimization:
# Check bundle sizedu -h dist/client/index.js# 1.0M dist/client/index.jsAfter modular imports:
# Check individual bundlesdu -h dist/client/*.js# 216K dist/client/components.js# 4.0K dist/client/hooks.js# 4.0K dist/client/charts.js# 4.0K dist/client/providers.jsMigration Guide
Section titled “Migration Guide”From Full Import to Modular
Section titled “From Full Import to Modular”Before:
import { AnalyticsDashboard, RechartsBarChart, useCubeQuery, CubeProvider} from 'drizzle-cube/client';After:
import { AnalyticsDashboard } from 'drizzle-cube/client/components';import { RechartsBarChart } from 'drizzle-cube/client/charts';import { useCubeQuery } from 'drizzle-cube/client/hooks';import { CubeProvider } from 'drizzle-cube/client/providers';Result: Same functionality, smaller bundle, better performance
Gradual Migration
Section titled “Gradual Migration”You can migrate gradually - both approaches work simultaneously:
// Mixed imports work fineimport { AnalyticsDashboard } from 'drizzle-cube/client'; // Full importimport { RechartsBarChart } from 'drizzle-cube/client/charts'; // Modular importThe bundler will deduplicate shared code automatically.
Best Practices
Section titled “Best Practices”- Start with modular imports for new applications
- Analyze your bundle regularly to identify optimization opportunities
- Use dynamic imports for large chart libraries when possible
- Configure tree shaking properly in your bundler
- Monitor bundle size in CI/CD pipelines
- Profile loading performance with different import strategies
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”Duplicate React instances:
# Ensure peer dependencies are properly installednpm ls react react-domTree shaking not working:
// Check package.json sideEffects setting{ "sideEffects": false // Enables aggressive tree shaking}Chunk loading errors:
- Verify public path configuration
- Check CORS settings for chunk loading
- Ensure proper caching headers
Performance Monitoring
Section titled “Performance Monitoring”Monitor bundle performance:
// Add bundle performance monitoringif (process.env.NODE_ENV === 'development') { import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { getCLS(console.log); getFID(console.log); getFCP(console.log); getLCP(console.log); getTTFB(console.log); });}Schema Diagram Feature (Optional)
Section titled “Schema Diagram Feature (Optional)”The AnalysisBuilder includes an optional schema diagram feature that visualizes cube relationships using an interactive ERD-style diagram. This feature requires additional dependencies (reactflow and dagre) and is disabled by default to keep bundle sizes small.
Enabling the Schema Diagram
Section titled “Enabling the Schema Diagram”- Install the optional dependencies:
npm install reactflow dagre- Enable the feature in your CubeProvider:
import { CubeProvider, AnalysisBuilder } from 'drizzle-cube/client';
function App() { return ( <CubeProvider apiOptions={{ apiUrl: '/api/cube' }} features={{ showSchemaDiagram: true }} > <AnalysisBuilder /> </CubeProvider> );}What You Get
Section titled “What You Get”When enabled, the AnalysisBuilder’s Schema Explorer shows a “Schema” tab alongside the “Fields” tab:
- Interactive ERD diagram showing cube relationships
- Click on cubes to expand/collapse their fields
- Click on fields to add them to your query
- Drag nodes to rearrange the diagram
- Auto-layout for automatic positioning
- Search to highlight matching fields across cubes
Bundle Impact
Section titled “Bundle Impact”| Configuration | Extra Bundle Size |
|---|---|
showSchemaDiagram: false (default) | 0 KB |
showSchemaDiagram: true | ~280 KB (reactflow + dagre) |
The schema diagram is loaded lazily - it only loads when the user clicks the “Schema” tab in the AnalysisBuilder, so even when enabled, there’s no initial load penalty until the user actually views the diagram.
When to Enable
Section titled “When to Enable”Enable the schema diagram feature when:
- You’re building a playground or exploration tool where users need to understand cube relationships
- Your cubes have complex relationships that are easier to understand visually
- Users need to discover available fields across related cubes
Keep it disabled (default) when:
- You’re building production dashboards where users don’t need to explore the schema
- Bundle size is critical and the ~280KB addition is not acceptable
- Users are familiar with the schema and don’t need visual exploration
The modular architecture of Drizzle Cube ensures you can build performant applications with optimal bundle sizes while maintaining full functionality.