@hydration-audit/core
v0.2.0
Published
Framework-agnostic analysis engine for JavaScript hydration costs
Readme
@hydration-audit/core
Framework-agnostic analysis engine for JavaScript hydration costs.
This is the core package of the Hydration Cost Visibility Platform. It provides the analysis pipeline, data model, configuration system, and issue detection rules.
Installation
npm install @hydration-audit/coreUsage
Programmatic API
import { analyze } from '@hydration-audit/core';
const report = await analyze({
cwd: '/path/to/project',
config: {
framework: 'astro',
thresholds: { islandBudget: 30_000 },
},
});
// Access the report
console.log(`Found ${report.totals.totalIslands} islands`);
console.log(`Total JS: ${report.totals.totalGzipSize} bytes (gzip)`);
console.log(`Issues: ${report.totals.totalIssues}`);
for (const island of report.islands) {
console.log(` ${island.component.name}: ${island.bundle.totalGzipSize}B`);
}Configuration
import { defineConfig, resolveConfig, loadConfig } from '@hydration-audit/core';
// Define a config with type checking
const userConfig = defineConfig({
framework: 'astro',
thresholds: { islandBudget: 50_000 },
});
// Load config from filesystem (cosmiconfig)
const loaded = await loadConfig('/path/to/project');
// Resolve partial config into full config with defaults
const config = resolveConfig(userConfig, '/path/to/project');Building a Custom Adapter
import type { FrameworkAdapter, AdapterContext, IslandComponent } from '@hydration-audit/core';
class MyAdapter implements FrameworkAdapter {
readonly name = 'my-framework';
readonly sourcePatterns = ['**/*.my'];
async extract(context: AdapterContext): Promise<IslandComponent[]> {
// Scan source files, find hydrated components
return [
{
name: 'MyComponent',
sourceFile: '/src/MyComponent.tsx',
pages: ['/'],
directive: 'client:load',
uiFramework: 'react',
metaFramework: 'my-framework',
},
];
}
}
// Use it
const report = await analyze({
adapter: new MyAdapter(),
});Data Model
Core Types
| Type | Description |
|---|---|
| IslandComponent | A hydrated component with name, source, directive, framework |
| BundleAnalysis | Gzip/brotli sizes, exclusive and shared chunk breakdown |
| HydrationIssue | A detected issue with type, severity, message, recommendation |
| EnrichedIsland | Component + bundle + issues combined |
| PageSummary | Per-page aggregation of islands and issues |
| AnalysisReport | The complete analysis output |
| FrameworkAdapter | Interface for framework-specific adapters |
| ResolvedConfig | Fully resolved configuration |
Issue Types
| Rule ID | Description |
|---|---|
| oversized-island | Island exceeds gzip size budget |
| eager-below-fold | client:load on below-fold component |
| idle-large-bundle | client:idle with large bundle |
| duplicate-framework | Multiple UI frameworks on same page |
| unnecessary-hydration | client:load with no interactivity |
| shared-chunk-bloat | Large shared chunk with low reuse |
| budget-exceeded | Page or site JS budget exceeded |
API Reference
analyze(options?)
Main entry point. Runs the full analysis pipeline.
Options:
config?: UserConfig— Partial config to mergeconfigPath?: string— Path to search for config fileadapter?: FrameworkAdapter— Pre-configured adaptercwd?: string— Working directoryverbose?: boolean— Enable debug logging
Returns: Promise<AnalysisReport>
defineConfig(config)
Type-safe config helper. Returns the config as-is.
loadConfig(searchFrom?)
Load config from filesystem using cosmiconfig.
resolveConfig(userConfig?, cwd?)
Merge a partial config with defaults. All paths resolved relative to cwd.
License
MIT
