Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions packages/bundlecheck/src/__tests__/cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,43 @@ describe("setCachedResult and getCachedResult", () => {
expect(getCachedResult(keyBrowser)?.rawSize).toBe(1000);
expect(getCachedResult(keyNode)?.rawSize).toBe(2000);
});

it("should preserve actual externals when key externals differ from result externals", () => {
/**
* This tests the scenario where:
* - User doesn't provide --external flag (key.externals = [])
* - But the bundler auto-detects react/react-dom from package.json
* (result.externals = ["react", "react-dom"])
* The cached result should return the actual computed externals, not the empty key externals.
*/
const key = normalizeCacheKey({
packageName: "@mantine/core",
version: "8.0.0",
exports: ["Button"],
platform: "browser",
gzipLevel: 5,
externals: [], // User didn't pass --external flag
noExternal: false,
});

const resultWithComputedExternals: BundleResult = {
packageName: "@mantine/core",
packageVersion: "8.0.0",
exports: ["Button"],
rawSize: 50000,
gzipSize: 12000,
gzipLevel: 5,
externals: ["react", "react-dom"], // Auto-detected from package dependencies
dependencies: ["@mantine/hooks", "react", "react-dom"],
platform: "browser",
};

setCachedResult(key, resultWithComputedExternals);
const cached = getCachedResult(key);

// The cached result should have the actual computed externals, not empty
expect(cached?.externals).toEqual(["react", "react-dom"]);
});
});

describe("clearCache", () => {
Expand Down
25 changes: 21 additions & 4 deletions packages/bundlecheck/src/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type CacheRow = {
dependencies: string;
display_name: string;
created_at: number;
actual_externals: string;
};

let db: Database.Database | null = null;
Expand Down Expand Up @@ -89,12 +90,22 @@ export function initCache(): Database.Database {
dependencies TEXT NOT NULL DEFAULT '[]',
display_name TEXT NOT NULL,
created_at INTEGER NOT NULL,
actual_externals TEXT NOT NULL DEFAULT '',
UNIQUE(package_name, version, exports, platform, gzip_level, externals, no_external)
);

CREATE INDEX IF NOT EXISTS idx_created_at ON bundle_cache(created_at);
`);

// Migration: Add actual_externals column if it doesn't exist (for existing databases).
try {
db.exec(
`ALTER TABLE bundle_cache ADD COLUMN actual_externals TEXT NOT NULL DEFAULT ''`,
);
} catch {
// Column already exists, ignore error.
}

return db;
}

Expand Down Expand Up @@ -178,15 +189,20 @@ export function getCachedResult(key: CacheKey): CachedBundleResult | null {
dependencies = [];
}

// Convert row to BundleResult.
/**
* Convert row to BundleResult.
* Use actual_externals (computed externals including auto-detected react/react-dom)
* if available, otherwise fall back to externals (for old cache entries).
*/
const externalsStr = row.actual_externals || row.externals;
return {
packageName: row.display_name,
packageVersion: row.version,
exports: row.exports ? row.exports.split(",").filter(Boolean) : [],
rawSize: row.raw_size,
gzipSize: row.gzip_size,
gzipLevel: row.gzip_level,
externals: row.externals ? row.externals.split(",").filter(Boolean) : [],
externals: externalsStr ? externalsStr.split(",").filter(Boolean) : [],
dependencies,
platform: row.platform as "browser" | "node",
};
Expand Down Expand Up @@ -214,8 +230,8 @@ export function setCachedResult(key: CacheKey, result: BundleResult): void {
const stmt = database.prepare(`
INSERT OR REPLACE INTO bundle_cache (
package_name, version, exports, platform, gzip_level, externals, no_external,
raw_size, gzip_size, dependencies, display_name, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
raw_size, gzip_size, dependencies, display_name, created_at, actual_externals
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);

stmt.run(
Expand All @@ -231,6 +247,7 @@ export function setCachedResult(key: CacheKey, result: BundleResult): void {
JSON.stringify(result.dependencies),
result.packageName,
Date.now(),
result.externals.slice().sort().join(","),
);

// Enforce max entries (LRU-style eviction based on created_at).
Expand Down