Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add cache invalidation on config change #862

Merged
merged 1 commit into from
Jan 18, 2025
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
24 changes: 24 additions & 0 deletions packages/cli/__tests__/compile-stylex-folder-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ describe('cache mechanism works as expected', () => {
expect(cacheContent).toHaveProperty('inputHash');
expect(cacheContent).toHaveProperty('outputHash');
expect(cacheContent).toHaveProperty('collectedCSS');
expect(cacheContent).toHaveProperty('configHash');
}
});

Expand All @@ -306,6 +307,28 @@ describe('cache mechanism works as expected', () => {
writeSpy.mockRestore();
});

test('recompiles when config changes', async () => {
config.styleXBundleName = 'stylex_bundle_new.css';
await compileDirectory(config);

// Ensure cache is rewritten due to cache invalidation
expect(writeSpy).toHaveBeenCalledTimes(3);

const cacheFiles = await fs.readdir(cachePath);
expect(cacheFiles.length).toEqual(3);

for (const cacheFile of cacheFiles) {
const cacheFilePath = path.join(cachePath, cacheFile);
const cacheContent = JSON.parse(
await fs.readFile(cacheFilePath, 'utf-8'),
);
expect(cacheContent).toHaveProperty('inputHash');
expect(cacheContent).toHaveProperty('outputHash');
expect(cacheContent).toHaveProperty('collectedCSS');
expect(cacheContent).toHaveProperty('configHash');
}
});

test('recompiles when input changes', async () => {
const mockFilePath = path.join(config.input, 'index.js');
const mockFileOutputPath = path.join(config.output, 'index.js');
Expand Down Expand Up @@ -386,6 +409,7 @@ describe('CLI works with a custom cache path', () => {
expect(cacheContent).toHaveProperty('inputHash');
expect(cacheContent).toHaveProperty('outputHash');
expect(cacheContent).toHaveProperty('collectedCSS');
expect(cacheContent).toHaveProperty('configHash');
}
});

Expand Down
18 changes: 17 additions & 1 deletion packages/cli/src/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,23 @@ export async function deleteCache(cachePath, filePath) {
}
}

export async function computeHash(filePath) {
export function computeStyleXConfigHash(config) {
// Excluding `input` and `output` paths to hash config settings
const configOptions = Object.fromEntries(
Object.entries(config).filter(
([key]) => key !== 'input' && key !== 'output',
),
);

const jsonRepresentation = JSON.stringify(
configOptions,
Object.keys(configOptions).sort(),
);

return hash(jsonRepresentation);
}

export async function computeFilePathHash(filePath) {
const absoluteFilePath = path.resolve(filePath);
const parsedFile = path.parse(absoluteFilePath);

Expand Down
15 changes: 10 additions & 5 deletions packages/cli/src/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import fs from 'fs';
import {
writeCache,
readCache,
computeHash,
computeFilePathHash,
computeStyleXConfigHash,
getDefaultCachePath,
} from './cache';
import {
Expand Down Expand Up @@ -102,19 +103,22 @@ export async function compileFile(
const outputFilePath = path.join(config.output, filePath);
const cachePath = config.cachePath || getDefaultCachePath();

const inputHash = await computeHash(inputFilePath);
const inputHash = await computeFilePathHash(inputFilePath);
let oldOutputHash = null;
if (fs.existsSync(outputFilePath)) {
oldOutputHash = await computeHash(outputFilePath);
oldOutputHash = await computeFilePathHash(outputFilePath);
}

const configHash = computeStyleXConfigHash(config);

const cacheData = await readCache(cachePath, filePath);

if (
cacheData &&
cacheData.inputHash === inputHash &&
oldOutputHash &&
cacheData.outputHash === oldOutputHash
cacheData.outputHash === oldOutputHash &&
cacheData.configHash === configHash
) {
console.log(`[stylex] Using cached CSS for: ${filePath}`);
config.state.styleXRules.set(filePath, cacheData.collectedCSS);
Expand All @@ -133,12 +137,13 @@ export async function compileFile(

writeCompiledJS(outputFilePath, code);

const newOutputHash = await computeHash(outputFilePath);
const newOutputHash = await computeFilePathHash(outputFilePath);

await writeCache(cachePath, filePath, {
inputHash,
outputHash: newOutputHash,
collectedCSS: rules,
configHash,
});
}
}
Expand Down
Loading